Skip to content

Commit 60774fb

Browse files
authored
Merge pull request #68450 from Azoy/fix-array-like
[IRGen] Some fixes for raw layout types and noncopyable types in the stdlib
2 parents de5e4a3 + 6fde84e commit 60774fb

File tree

7 files changed

+180
-25
lines changed

7 files changed

+180
-25
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3081,7 +3081,8 @@ static void emitInitializeRawLayout(IRGenFunction &IGF, SILType likeType,
30813081
auto initRawAvail = IGF.IGM.Context.getInitRawStructMetadataAvailability();
30823082

30833083
if (!IGF.IGM.Context.LangOpts.DisableAvailabilityChecking &&
3084-
!deploymentAvailability.isContainedIn(initRawAvail)) {
3084+
!deploymentAvailability.isContainedIn(initRawAvail) &&
3085+
!IGF.IGM.getSwiftModule()->isStdlibModule()) {
30853086
emitInitializeRawLayoutOld(IGF, likeType, count, T, metadata, collector);
30863087
return;
30873088
}

lib/IRGen/GenReflection.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,28 @@ getTypeRefByFunction(IRGenModule &IGM,
279279
llvm::Instruction *br = nullptr;
280280
llvm::BasicBlock *supportedBB = nullptr;
281281
if (useForwardCompatibility) {
282-
auto runtimeSupportsNoncopyableTypesSymbol
283-
= IGM.Module.getOrInsertGlobal("swift_runtimeSupportsNoncopyableTypes",
284-
IGM.Int8Ty);
285-
cast<llvm::GlobalVariable>(runtimeSupportsNoncopyableTypesSymbol)
286-
->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
282+
llvm::Value *runtimeSupportsNoncopyableTypesSymbol = nullptr;
283+
284+
// This is weird. When building the stdlib, we don't have access to
285+
// the swift_runtimeSupportsNoncopyableTypes symbol in the Swift.o,
286+
// so we'll emit an adrp + ldr to resolve the GOT address. However,
287+
// this symbol is defined as an abolsute in the runtime object files
288+
// to address 0x0 right now and ld doesn't quite understand how to
289+
// fixup this GOT address when merging the runtime and stdlib. Just
290+
// unconditionally fail the branch.
291+
//
292+
// Note: When the value of this symbol changes, this MUST be
293+
// updated.
294+
if (IGM.getSwiftModule()->isStdlibModule()) {
295+
runtimeSupportsNoncopyableTypesSymbol
296+
= llvm::ConstantInt::get(IGM.Int8Ty, 0);
297+
} else {
298+
runtimeSupportsNoncopyableTypesSymbol
299+
= IGM.Module.getOrInsertGlobal(
300+
"swift_runtimeSupportsNoncopyableTypes", IGM.Int8Ty);
301+
cast<llvm::GlobalVariable>(runtimeSupportsNoncopyableTypesSymbol)
302+
->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
303+
}
287304

288305
auto runtimeSupportsNoncopyableTypes
289306
= IGF.Builder.CreateIsNotNull(runtimeSupportsNoncopyableTypesSymbol,

lib/IRGen/GenStruct.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,35 @@ namespace {
990990
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
991991
}
992992

993+
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
994+
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
995+
996+
// If we have a raw layout struct who is fixed size, it means the
997+
// layout of the struct is fully concrete.
998+
if (rawLayout) {
999+
// Defer to this fixed type info for type layout if the raw layout
1000+
// specifies size and alignment.
1001+
if (rawLayout->getSizeAndAlignment()) {
1002+
return IGM.typeLayoutCache.getOrCreateTypeInfoBasedEntry(*this, T);
1003+
}
1004+
1005+
auto likeType = rawLayout->getResolvedLikeType(decl)->getCanonicalType();
1006+
SILType loweredLikeType = IGM.getLoweredType(likeType);
1007+
1008+
// The given struct type T that we're building is fully concrete, but
1009+
// our like type is still in terms of the potential archetype of the
1010+
// type.
1011+
auto subs = T.getASTType()->getContextSubstitutionMap(
1012+
IGM.getSwiftModule(), decl);
1013+
1014+
loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs);
1015+
1016+
// Array like raw layouts are still handled correctly even though the
1017+
// type layout entry is only that of the like type.
1018+
return IGM.getTypeInfo(loweredLikeType)
1019+
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
1020+
}
1021+
9931022
std::vector<TypeLayoutEntry *> fields;
9941023
for (auto &field : getFields()) {
9951024
auto fieldTy = field.getType(IGM, T);
@@ -1082,27 +1111,19 @@ namespace {
10821111
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
10831112
}
10841113

1085-
std::vector<TypeLayoutEntry *> fields;
1086-
for (auto &field : getFields()) {
1087-
auto fieldTy = field.getType(IGM, T);
1088-
fields.push_back(
1089-
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy, useStructLayouts));
1090-
}
1091-
10921114
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
10931115
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
10941116

10951117
// If we have a raw layout struct who is non-fixed size, it means the
10961118
// layout of the struct is dependent on the archetype of the thing it's
10971119
// like.
10981120
if (rawLayout) {
1099-
SILType loweredLikeType;
1121+
// Note: We don't have to handle the size and alignment case here for
1122+
// raw layout because those are always fixed, so only dependent layouts
1123+
// will be non-fixed.
11001124

1101-
if (auto likeType = rawLayout->getResolvedScalarLikeType(decl)) {
1102-
loweredLikeType = IGM.getLoweredType(*likeType);
1103-
} else if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
1104-
loweredLikeType = IGM.getLoweredType(likeArray->first);
1105-
}
1125+
auto likeType = rawLayout->getResolvedLikeType(decl)->getCanonicalType();
1126+
SILType loweredLikeType = IGM.getLoweredType(likeType);
11061127

11071128
// The given struct type T that we're building may be in a generic
11081129
// environment that is different than that which was built our
@@ -1113,10 +1134,18 @@ namespace {
11131134

11141135
loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs);
11151136

1116-
return IGM.getTypeInfo(loweredLikeType).buildTypeLayoutEntry(IGM,
1117-
loweredLikeType, useStructLayouts);
1137+
// Array like raw layouts are still handled correctly even though the
1138+
// type layout entry is only that of the like type.
1139+
return IGM.getTypeInfo(loweredLikeType)
1140+
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
11181141
}
11191142

1143+
std::vector<TypeLayoutEntry *> fields;
1144+
for (auto &field : getFields()) {
1145+
auto fieldTy = field.getType(IGM, T);
1146+
fields.push_back(
1147+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy, useStructLayouts));
1148+
}
11201149
assert(!fields.empty() &&
11211150
"Empty structs should not be NonFixedStructTypeInfo");
11221151

stdlib/public/runtime/Metadata.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ using namespace metadataimpl;
8585
// types, so we explicitly define this symbol to be zero for now. Binaries
8686
// weak-import this symbol so they will resolve it to a zero address on older
8787
// runtimes as well.
88+
//
89+
// Note: If this symbol's value ever gets updated, the corresponding condition
90+
// handled by IRGen MUST be updated in tandem.
8891
__asm__(" .globl _swift_runtimeSupportsNoncopyableTypes\n");
8992
__asm__(".set _swift_runtimeSupportsNoncopyableTypes, 0\n");
9093
#endif
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
1+
import Builtin
2+
13
extension Foo where T == Int32 {
24

35
}
46

57
public func foo(_: borrowing Foo<Int32>) {}
8+
9+
@_rawLayout(size: 4, alignment: 4)
10+
public struct Int32Fake: ~Copyable {
11+
var address: UnsafeMutablePointer<Int32> {
12+
.init(Builtin.unprotectedAddressOfBorrow(self))
13+
}
14+
}
15+
16+
@_rawLayout(like: T)
17+
public struct UnsafeCell<T>: ~Copyable {
18+
var address: UnsafeMutablePointer<T> {
19+
.init(Builtin.unprotectedAddressOfBorrow(self))
20+
}
21+
}
22+
23+
@_rawLayout(likeArrayOf: T, count: 3)
24+
public struct SmallVectorOf3<T>: ~Copyable {
25+
var address: UnsafeMutablePointer<T> {
26+
.init(Builtin.unprotectedAddressOfBorrow(self))
27+
}
28+
}

test/IRGen/raw_layout.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ struct PaddedCell<T>: ~Copyable {}
9898
@_rawLayout(likeArrayOf: T, count: 8)
9999
struct SmallVectorBuf<T>: ~Copyable {}
100100

101+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}14SmallVectorOf3VWV" = {{.*}} %swift.vwtable
102+
// size
103+
// CHECK-SAME: , {{i64|i32}} 0
104+
// stride
105+
// CHECK-SAME: , {{i64|i32}} 0
106+
// flags: alignment 0, incomplete
107+
// CHECK-SAME: , <i32 0x400000>
108+
@_rawLayout(likeArrayOf: T, count: 3)
109+
struct SmallVectorOf3<T>: ~Copyable {}
110+
101111
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}8UsesCellVWV" = {{.*}} %swift.vwtable
102112
// size
103113
// CHECK-SAME: , {{i64|i32}} 8
@@ -110,6 +120,28 @@ struct UsesCell: ~Copyable {
110120
let specialInt: Cell<Int32>
111121
}
112122

123+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}13BufferOf3BoolVWV" = {{.*}} %swift.vwtable
124+
// size
125+
// CHECK-SAME: , {{i64|i32}} 3
126+
// stride
127+
// CHECK-SAME: , {{i64|i32}} 3
128+
// flags: alignment 0, noncopyable
129+
// CHECK-SAME: , <i32 0x800000>
130+
struct BufferOf3Bool: ~Copyable {
131+
let buffer: SmallVectorOf3<Bool>
132+
}
133+
134+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}9BadBufferVWV" = {{.*}} %swift.vwtable
135+
// size
136+
// CHECK-SAME: , {{i64|i32}} 48
137+
// stride
138+
// CHECK-SAME: , {{i64|i32}} 48
139+
// flags: alignment 7, noncopyable, is not inline
140+
// CHECK-SAME: , <i32 0x820007>
141+
struct BadBuffer: ~Copyable {
142+
let buffer: SmallVectorOf3<Int64?>
143+
}
144+
113145
// Dependent layout metadata initialization:
114146

115147
// Cell<T>

test/IRGen/raw_layout_multifile.swift

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
1-
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -emit-ir -primary-file %s %S/Inputs/raw_layout_multifile_b.swift
2-
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -emit-ir %s -primary-file %S/Inputs/raw_layout_multifile_b.swift
3-
4-
import Swift
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/chex.py < %s > %t/raw_layout_multifile.swift
3+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -enable-experimental-feature RawLayout -emit-ir -O -disable-availability-checking %s %S/Inputs/raw_layout_multifile_b.swift | %FileCheck %t/raw_layout_multifile.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
54

65
@_rawLayout(like: Int32)
76
public struct Foo<T>: ~Copyable {}
7+
8+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}5MyIntVWV" = {{.*}} %swift.vwtable
9+
// size
10+
// CHECK-SAME: , {{i64|i32}} 4
11+
// stride
12+
// CHECK-SAME: , {{i64|i32}} 4
13+
// flags: alignment 3, noncopyable
14+
// CHECK-SAME: , <i32 0x800003>
15+
struct MyInt: ~Copyable {
16+
let x: Int32Fake
17+
}
18+
19+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}9BadBufferVWV" = {{.*}} %swift.vwtable
20+
// size
21+
// CHECK-SAME: , {{i64|i32}} 48
22+
// stride
23+
// CHECK-SAME: , {{i64|i32}} 48
24+
// flags: alignment 7, noncopyable, is not inline
25+
// CHECK-SAME: , <i32 0x820007>
26+
struct BadBuffer: ~Copyable {
27+
let buf = SmallVectorOf3<Int64?>()
28+
}
29+
30+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}5WeirdVWV" = {{.*}} %swift.vwtable
31+
// size
32+
// CHECK-SAME: , {{i64|i32}} 8
33+
// stride
34+
// CHECK-SAME: , {{i64|i32}} 8
35+
// flags: alignment 7, noncopyable
36+
// CHECK-SAME: , <i32 0x800007>
37+
struct Weird: ~Copyable {
38+
let value = UnsafeCell<Int64>()
39+
}
40+
41+
// Force emission of Weird's descriptor to be lazy...
42+
public func something() -> Int64 {
43+
let x = Weird()
44+
return x.value.address.pointee
45+
}
46+
47+
// Force emission of BadBuffer's descriptor to be lazy...
48+
public func something2() -> Int64? {
49+
let buf = BadBuffer()
50+
return buf.buf.address[1]
51+
}
52+
53+
// Force emission of MyInt's descriptor to be lazy...
54+
public func something3() -> Int32 {
55+
let x = MyInt(x: Int32Fake())
56+
return x.x.address.pointee
57+
}

0 commit comments

Comments
 (0)