Skip to content

Commit ab143ee

Browse files
committed
Some fixes for raw layout types and noncopyable types in the stdlib
1 parent 973a506 commit ab143ee

File tree

7 files changed

+147
-26
lines changed

7 files changed

+147
-26
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: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,29 @@ 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+
auto likeType = rawLayout->getResolvedLikeType(decl)->getCanonicalType();
1000+
SILType loweredLikeType = IGM.getLoweredType(likeType);
1001+
1002+
// The given struct type T that we're building is fully concrete, but
1003+
// our like type is still in terms of the potential archetype of the
1004+
// type.
1005+
auto subs = T.getASTType()->getContextSubstitutionMap(
1006+
IGM.getSwiftModule(), decl);
1007+
1008+
loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs);
1009+
1010+
// Array like raw layouts are still handled correctly even though the
1011+
// type layout entry is only that of the like type.
1012+
return IGM.getTypeInfo(loweredLikeType)
1013+
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
1014+
}
1015+
9931016
std::vector<TypeLayoutEntry *> fields;
9941017
for (auto &field : getFields()) {
9951018
auto fieldTy = field.getType(IGM, T);
@@ -1082,27 +1105,15 @@ namespace {
10821105
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
10831106
}
10841107

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-
10921108
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
10931109
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
10941110

10951111
// If we have a raw layout struct who is non-fixed size, it means the
10961112
// layout of the struct is dependent on the archetype of the thing it's
10971113
// like.
10981114
if (rawLayout) {
1099-
SILType loweredLikeType;
1100-
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-
}
1115+
auto likeType = rawLayout->getResolvedLikeType(decl)->getCanonicalType();
1116+
SILType loweredLikeType = IGM.getLoweredType(likeType);
11061117

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

11141125
loweredLikeType = loweredLikeType.subst(IGM.getSILModule(), subs);
11151126

1116-
return IGM.getTypeInfo(loweredLikeType).buildTypeLayoutEntry(IGM,
1117-
loweredLikeType, useStructLayouts);
1127+
// Array like raw layouts are still handled correctly even though the
1128+
// type layout entry is only that of the like type.
1129+
return IGM.getTypeInfo(loweredLikeType)
1130+
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
11181131
}
11191132

1133+
std::vector<TypeLayoutEntry *> fields;
1134+
for (auto &field : getFields()) {
1135+
auto fieldTy = field.getType(IGM, T);
1136+
fields.push_back(
1137+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy, useStructLayouts));
1138+
}
11201139
assert(!fields.empty() &&
11211140
"Empty structs should not be NonFixedStructTypeInfo");
11221141

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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
import Builtin
2+
13
extension Foo where T == Int32 {
24

35
}
46

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

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: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,40 @@
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_]*}}9BadBufferVWV" = {{.*}} %swift.vwtable
9+
// size
10+
// CHECK-SAME: , {{i64|i32}} 48
11+
// stride
12+
// CHECK-SAME: , {{i64|i32}} 48
13+
// flags: alignment 7, noncopyable, is not inline
14+
// CHECK-SAME: , <i32 0x820007>
15+
struct BadBuffer: ~Copyable {
16+
let buf = SmallVectorOf3<Int64?>()
17+
}
18+
19+
// CHECK-LABEL: @"$s{{[A-Za-z0-9_]*}}5WeirdVWV" = {{.*}} %swift.vwtable
20+
// size
21+
// CHECK-SAME: , {{i64|i32}} 8
22+
// stride
23+
// CHECK-SAME: , {{i64|i32}} 8
24+
// flags: alignment 7, noncopyable
25+
// CHECK-SAME: , <i32 0x800007>
26+
struct Weird: ~Copyable {
27+
let value = UnsafeCell<Int64>()
28+
}
29+
30+
// Force emission of Weird's descriptor to be lazy...
31+
public func something() -> Int64 {
32+
let x = Weird()
33+
return x.value.address.pointee
34+
}
35+
36+
// Force emission of BadBuffer's descriptor to be lazy...
37+
public func something2() -> Int64? {
38+
let buf = BadBuffer()
39+
return buf.buf.address[1]
40+
}

0 commit comments

Comments
 (0)