Skip to content

Commit 3b741ee

Browse files
authored
Merge pull request swiftlang#76303 from Azoy/rawlayout-fixes
[IRGen] Collect metadata from like type and add type information when GEPing into raw layouts
2 parents ba8b7e4 + 389716a commit 3b741ee

File tree

6 files changed

+136
-63
lines changed

6 files changed

+136
-63
lines changed

include/swift/SIL/SILType.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,12 @@ class SILType {
909909
return sd->getAttrs().getAttribute<RawLayoutAttr>();
910910
}
911911

912+
/// If this is a raw layout type, returns the substituted like type.
913+
Type getRawLayoutSubstitutedLikeType() const;
914+
915+
/// If this is a raw layout type, returns the substituted count type.
916+
Type getRawLayoutSubstitutedCountType() const;
917+
912918
/// If this is a SILBoxType, return getSILBoxFieldType(). Otherwise, return
913919
/// SILType().
914920
///

lib/IRGen/GenRecord.h

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -297,31 +297,31 @@ class RecordTypeInfoImpl : public Base,
297297
std::function<void
298298
(const TypeInfo &, SILType, Address, Address)> body) const {
299299
if (rawLayout->shouldMoveAsLikeType()) {
300-
// Because we have a rawlayout attribute, we know this has to be a struct.
301-
auto structDecl = T.getStructOrBoundGenericStruct();
302-
303-
if (auto likeType = rawLayout->getResolvedScalarLikeType(structDecl)) {
304-
auto astT = T.getASTType();
305-
auto subs = astT->getContextSubstitutionMap();
306-
auto loweredLikeType = IGF.IGM.getLoweredType(likeType->subst(subs));
307-
auto &likeTypeInfo = IGF.IGM.getTypeInfo(loweredLikeType);
308-
300+
auto likeType = T.getRawLayoutSubstitutedLikeType();
301+
auto loweredLikeType = IGF.IGM.getLoweredType(likeType);
302+
auto &likeTypeInfo = IGF.IGM.getTypeInfo(loweredLikeType);
303+
304+
// Fixup src/dest address element types because currently they are in
305+
// terms of the raw layout type's [n x i8] where we're at a point to use
306+
// the like type's concrete storage type.
307+
src = Address(src.getAddress(), likeTypeInfo.getStorageType(),
308+
src.getAlignment());
309+
dest = Address(dest.getAddress(), likeTypeInfo.getStorageType(),
310+
dest.getAlignment());
311+
312+
// If we're a scalar, then we only need to run the body once.
313+
if (rawLayout->getScalarLikeType()) {
309314
body(likeTypeInfo, loweredLikeType, dest, src);
310315
}
311316

312-
if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(structDecl)) {
313-
auto likeType = likeArray->first;
314-
auto countType = likeArray->second;
315-
316-
auto astT = T.getASTType();
317-
auto subs = astT->getContextSubstitutionMap();
318-
auto loweredLikeType = IGF.IGM.getLoweredType(likeType.subst(subs));
319-
auto &likeTypeInfo = IGF.IGM.getTypeInfo(loweredLikeType);
320-
countType = countType.subst(subs);
317+
// Otherwise, emit a loop that calls body N times where N is the count
318+
// of the array variant. This could be generic in which case we need to
319+
// pull the value out of metadata or it could be a constant integer.
320+
if (rawLayout->getArrayLikeTypeAndCount()) {
321+
auto countType = T.getRawLayoutSubstitutedCountType()->getCanonicalType();
321322

322-
IGF.emitLoopOverElements(likeTypeInfo, loweredLikeType,
323-
countType->getCanonicalType(), dest, src,
324-
[&](Address dest, Address src) {
323+
IGF.emitLoopOverElements(likeTypeInfo, loweredLikeType, countType,
324+
dest, src, [&](Address dest, Address src) {
325325
body(likeTypeInfo, loweredLikeType, dest, src);
326326
});
327327
}
@@ -555,6 +555,23 @@ class RecordTypeInfoImpl : public Base,
555555
auto fType = field.getType(collector.IGF.IGM, T);
556556
field.getTypeInfo().collectMetadataForOutlining(collector, fType);
557557
}
558+
559+
// If we're a raw layout type, collect metadata from our like type and count
560+
// as well.
561+
if (auto likeType = T.getRawLayoutSubstitutedLikeType()) {
562+
auto loweredLikeType = collector.IGF.IGM.getLoweredType(likeType);
563+
collector.IGF.IGM.getTypeInfo(loweredLikeType)
564+
.collectMetadataForOutlining(collector, loweredLikeType);
565+
566+
if (auto countType = T.getRawLayoutSubstitutedCountType()) {
567+
if (countType->isValueParameter()) {
568+
auto loweredCountType = collector.IGF.IGM.getLoweredType(countType);
569+
collector.IGF.IGM.getTypeInfo(loweredCountType)
570+
.collectMetadataForOutlining(collector, loweredCountType);
571+
}
572+
}
573+
}
574+
558575
collector.collectTypeMetadata(T);
559576
}
560577
};

lib/IRGen/GenStruct.cpp

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,30 +1007,23 @@ namespace {
10071007
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
10081008
}
10091009

1010-
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
1011-
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
1012-
10131010
// If we have a raw layout struct who is fixed size, it means the
10141011
// layout of the struct is fully concrete.
1015-
if (rawLayout) {
1012+
if (auto rawLayout = T.getRawLayout()) {
10161013
// Defer to this fixed type info for type layout if the raw layout
10171014
// specifies size and alignment.
10181015
if (rawLayout->getSizeAndAlignment()) {
10191016
return IGM.typeLayoutCache.getOrCreateTypeInfoBasedEntry(*this, T);
10201017
}
10211018

1022-
// The given struct type T that we're building is fully concrete, but
1023-
// our like type is still in terms of the potential archetype of the
1024-
// type.
1025-
auto subs = T.getASTType()->getContextSubstitutionMap(decl);
1026-
auto likeType = rawLayout->getResolvedLikeType(decl).subst(subs);
1027-
auto loweredLikeType = IGM.getLoweredType(likeType->getCanonicalType());
1019+
auto likeType = T.getRawLayoutSubstitutedLikeType();
1020+
auto loweredLikeType = IGM.getLoweredType(likeType);
10281021
auto likeTypeLayout = IGM.getTypeInfo(loweredLikeType)
10291022
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
10301023

10311024
// If we're an array, use the ArrayLayoutEntry.
1032-
if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
1033-
auto countType = likeArray->second.subst(subs)->getCanonicalType();
1025+
if (rawLayout->getArrayLikeTypeAndCount()) {
1026+
auto countType = T.getRawLayoutSubstitutedCountType()->getCanonicalType();
10341027
return IGM.typeLayoutCache.getOrCreateArrayEntry(likeTypeLayout,
10351028
loweredLikeType,
10361029
countType);
@@ -1133,29 +1126,22 @@ namespace {
11331126
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
11341127
}
11351128

1136-
auto decl = T.getASTType()->getStructOrBoundGenericStruct();
1137-
auto rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
1138-
11391129
// If we have a raw layout struct who is non-fixed size, it means the
11401130
// layout of the struct is dependent on the archetype of the thing it's
11411131
// like.
1142-
if (rawLayout) {
1132+
if (auto rawLayout = T.getRawLayout()) {
11431133
// Note: We don't have to handle the size and alignment case here for
11441134
// raw layout because those are always fixed, so only dependent layouts
11451135
// will be non-fixed.
11461136

1147-
// The given struct type T that we're building is fully concrete, but
1148-
// our like type is still in terms of the potential archetype of the
1149-
// type.
1150-
auto subs = T.getASTType()->getContextSubstitutionMap(decl);
1151-
auto likeType = rawLayout->getResolvedLikeType(decl).subst(subs);
1137+
auto likeType = T.getRawLayoutSubstitutedLikeType();
11521138
auto loweredLikeType = IGM.getLoweredType(likeType->getCanonicalType());
11531139
auto likeTypeLayout = IGM.getTypeInfo(loweredLikeType)
11541140
.buildTypeLayoutEntry(IGM, loweredLikeType, useStructLayouts);
11551141

11561142
// If we're an array, use the ArrayLayoutEntry.
1157-
if (auto likeArray = rawLayout->getResolvedArrayLikeTypeAndCount(decl)) {
1158-
auto countType = likeArray->second.subst(subs)->getCanonicalType();
1143+
if (rawLayout->getArrayLikeTypeAndCount()) {
1144+
auto countType = T.getRawLayoutSubstitutedCountType()->getCanonicalType();
11591145
return IGM.typeLayoutCache.getOrCreateArrayEntry(likeTypeLayout,
11601146
loweredLikeType,
11611147
countType);

lib/IRGen/StructLayout.cpp

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
8585
rawLayout = decl->getAttrs().getAttribute<RawLayoutAttr>();
8686
}
8787
if (rawLayout && type) {
88-
auto sd = cast<StructDecl>(decl);
8988
IsKnownTriviallyDestroyable = triviallyDestroyable;
9089
IsKnownBitwiseTakable = bitwiseTakable;
9190
SpareBits.clear();
@@ -112,31 +111,19 @@ StructLayout::StructLayout(IRGenModule &IGM, std::optional<CanType> type,
112111
IsFixedLayout = true;
113112
IsKnownAlwaysFixedSize = IsFixedSize;
114113
} else {
115-
std::optional<Type> likeType = std::nullopt;
116-
std::optional<Type> countType = std::nullopt;
114+
auto loweredType = IGM.getLoweredType(*type);
117115

118-
if (auto like = rawLayout->getResolvedScalarLikeType(sd)) {
119-
likeType = like;
120-
}
116+
Type likeType = loweredType.getRawLayoutSubstitutedLikeType();
117+
std::optional<Type> countType = std::nullopt;
121118

122-
if (auto like = rawLayout->getResolvedArrayLikeTypeAndCount(sd)) {
123-
likeType = like->first;
124-
countType = like->second;
119+
if (rawLayout->getArrayLikeTypeAndCount()) {
120+
countType = loweredType.getRawLayoutSubstitutedCountType();
125121
}
126122

127-
// If our likeType is dependent, then all calls to try and lay it out will
128-
// be non-fixed, but in a concrete case we want a fixed layout, so try to
129-
// substitute it out.
130-
auto subs = (*type)->getContextSubstitutionMap();
131-
auto loweredLikeType = IGM.getLoweredType(likeType->subst(subs));
123+
auto loweredLikeType = IGM.getLoweredType(likeType);
132124
auto &likeTypeInfo = IGM.getTypeInfo(loweredLikeType);
133125
auto likeFixedType = dyn_cast<FixedTypeInfo>(&likeTypeInfo);
134126

135-
// Substitute our count type if we have one.
136-
if (countType) {
137-
countType = countType->subst(subs);
138-
}
139-
140127
// Take layout attributes from the like type.
141128
//
142129
// We can only fixup the type's layout when either this is a scalar and

lib/SIL/IR/SILType.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,38 @@ bool SILType::isSendable(SILFunction *fn) const {
12561256
return getASTType()->isSendableType();
12571257
}
12581258

1259+
Type SILType::getRawLayoutSubstitutedLikeType() const {
1260+
auto rawLayout = getRawLayout();
1261+
1262+
if (!rawLayout)
1263+
return Type();
1264+
1265+
if (rawLayout->getSizeAndAlignment())
1266+
return Type();
1267+
1268+
auto structDecl = getStructOrBoundGenericStruct();
1269+
auto likeType = rawLayout->getResolvedLikeType(structDecl);
1270+
auto astT = getASTType();
1271+
auto subs = astT->getContextSubstitutionMap();
1272+
return likeType.subst(subs);
1273+
}
1274+
1275+
Type SILType::getRawLayoutSubstitutedCountType() const {
1276+
auto rawLayout = getRawLayout();
1277+
1278+
if (!rawLayout)
1279+
return Type();
1280+
1281+
if (rawLayout->getSizeAndAlignment() || rawLayout->getScalarLikeType())
1282+
return Type();
1283+
1284+
auto structDecl = getStructOrBoundGenericStruct();
1285+
auto countType = rawLayout->getResolvedCountType(structDecl);
1286+
auto astT = getASTType();
1287+
auto subs = astT->getContextSubstitutionMap();
1288+
return countType.subst(subs);
1289+
}
1290+
12591291
std::optional<DiagnosticBehavior>
12601292
SILType::getConcurrencyDiagnosticBehavior(SILFunction *fn) const {
12611293
auto declRef = fn->getDeclRef();

test/IRGen/stdlib/Mutex.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/chex.py < %s > %t/Mutex.swift
3+
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -enable-experimental-feature ValueGenerics -emit-ir -disable-availability-checking -I %S/Inputs -cxx-interoperability-mode=upcoming-swift -module-name stdlib %t/Mutex.swift | %FileCheck %t/Mutex.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
4+
5+
// REQUIRES: synchronization
6+
7+
import Synchronization
8+
9+
struct GenericMutex<T>: ~Copyable {
10+
let mutex: Mutex<T> // this previously crashed the compiler
11+
}
12+
13+
// Force emission of GenericMutex...
14+
// CHECK: %T6stdlib12GenericMutexVyytG
15+
func forceGenericMutex() -> GenericMutex<Void> {
16+
GenericMutex(mutex: Mutex(()))
17+
}
18+
19+
final class Awaitable<Value, Failure>: Sendable where Value: Sendable, Failure: Error {
20+
struct State {
21+
var pendingConsumers: [CheckedContinuation<Value, Failure>] = []
22+
var result: Result<Value, Failure>?
23+
}
24+
25+
let state: Mutex<State> // This previously crashed the compiler...
26+
27+
init() {
28+
self.state = Mutex(.init())
29+
}
30+
}
31+
32+
// CHECK: define {{.*}} ptr @"$s15Synchronization5MutexVy6stdlib9AwaitableC5StateVyxq__GGs8SendableRzs5ErrorR_r0_lWOb"(ptr [[SRC:%.*]], ptr [[DEST:%.*]], ptr {{%.*}}, ptr {{%.*}}, ptr {{%.*}}, ptr {{%.*}}, ptr {{%.*}}, ptr {{%.*}}, ptr [[MUTEX:%.*]])
33+
// CHECK: [[DEST_HANDLE_PTR:%.*]] = getelementptr inbounds %T15Synchronization5MutexV, ptr [[DEST]], i32 0, i32 0
34+
// CHECK: [[SRC_HANDLE_PTR:%.*]] = getelementptr inbounds %T15Synchronization5MutexV, ptr [[SRC]], i32 0, i32 0
35+
// CHECK: call void @llvm.memcpy.p0.p0.i{{32|64}}(ptr {{.*}} [[DEST_HANDLE_PTR]], ptr {{.*}} [[SRC_HANDLE_PTR]], i{{32|64}} {{.*}}, i1 false)
36+
// CHECK: [[DEST_MUTEX_VALUE_OFFSET_PTR:%.*]] = getelementptr inbounds i32, ptr [[MUTEX]], i{{32|64}} 7
37+
// CHECK: [[DEST_MUTEX_VALUE_OFFSET:%.*]] = load i32, ptr [[DEST_MUTEX_VALUE_OFFSET_PTR]]
38+
// CHECK: [[DEST_VALUE_PTR:%.*]] = getelementptr inbounds i8, ptr [[DEST]], i32 [[DEST_MUTEX_VALUE_OFFSET]]
39+
// CHECK: [[SRC_MUTEX_VALUE_OFFSET_PTR:%.*]] = getelementptr inbounds i32, ptr [[MUTEX]], i{{32|64}} 7
40+
// CHECK: [[SRC_MUTEX_VALUE_OFFSET:%.*]] = load i32, ptr [[SRC_MUTEX_VALUE_OFFSET_PTR]]
41+
// CHECK: [[SRC_VALUE_PTR:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i32 [[SRC_MUTEX_VALUE_OFFSET]]
42+
43+
// These GEPs used to cause compiler crashes because they were incorrectly typed...
44+
// CHECK: [[DEST_PENDING_CONSUMERS_PTR:%.*]] = getelementptr inbounds %T6stdlib9AwaitableC5StateV, ptr [[DEST_VALUE_PTR]], i32 0, i32 0
45+
// CHECK: [[SRC_PENDING_CONSUMERS_PTR:%.*]] = getelementptr inbounds %T6stdlib9AwaitableC5StateV, ptr [[SRC_VALUE_PTR]], i32 0, i32 0

0 commit comments

Comments
 (0)