Skip to content

Commit 36dd2c9

Browse files
authored
[SilOpt] Add new layout type _TrivialStride and add pre-specialization suppport for it (#70308)
rdar://119329771 This layout allows adding pre-specializations for trivial types that have a different size, but the same stride. This is especially useful for collections, where the stride is the important factor.
1 parent 568b682 commit 36dd2c9

19 files changed

+114
-21
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ now codified into the ABI; the index 0 is therefore reserved.
948948
LAYOUT-CONSTRAINT ::= 'm' LAYOUT-SIZE // Trivial of size at most N bits
949949
LAYOUT-CONSTRAINT ::= 'U' // Unknown layout
950950
LAYOUT-CONSTRAINT ::= 'B' // BridgeObject
951+
LAYOUT-CONSTRAINT ::= 'S' // TrivialStride
951952

952953
LAYOUT-SIZE ::= INDEX // Size only
953954
LAYOUT-SIZE-AND-ALIGNMENT ::= INDEX INDEX // Size followed by alignment

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ IDENTIFIER_WITH_NAME(NativeRefCountedObjectLayout, "_NativeRefCountedObject")
178178
IDENTIFIER_WITH_NAME(ClassLayout, "_Class")
179179
IDENTIFIER_WITH_NAME(NativeClassLayout, "_NativeClass")
180180
IDENTIFIER_WITH_NAME(BridgeObjectLayout, "_BridgeObject")
181+
IDENTIFIER_WITH_NAME(TrivialStrideLayout, "_TrivialStride")
181182

182183
// Operators
183184
IDENTIFIER_WITH_NAME(MatchOperator, "~=")

include/swift/AST/LayoutConstraint.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class LayoutConstraintInfo
114114

115115
bool isBridgeObject() const { return isBridgeObject(Kind); }
116116

117+
bool isTrivialStride() const { return isTrivialStride(Kind); }
118+
117119
unsigned getTrivialSizeInBytes() const {
118120
assert(isKnownSizeTrivial());
119121
return (SizeInBits + 7) / 8;
@@ -155,6 +157,11 @@ class LayoutConstraintInfo
155157
return 8*8;
156158
}
157159

160+
unsigned getTrivialStrideInBits() const {
161+
assert(isTrivialStride());
162+
return SizeInBits;
163+
}
164+
158165
operator bool() const {
159166
return isKnownLayout();
160167
}
@@ -204,6 +211,8 @@ class LayoutConstraintInfo
204211

205212
static bool isBridgeObject(LayoutConstraintKind Kind);
206213

214+
static bool isTrivialStride(LayoutConstraintKind Kind);
215+
207216
/// Uniquing for the LayoutConstraintInfo.
208217
void Profile(llvm::FoldingSetNodeID &ID) {
209218
Profile(ID, Kind, SizeInBits, Alignment);

include/swift/AST/LayoutConstraintKind.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ enum class LayoutConstraintKind : uint8_t {
4141
NativeRefCountedObject,
4242
// It is a layout constraint representing a bridge object
4343
BridgeObject,
44-
LastLayout = BridgeObject,
44+
// It is a layout constraint representing a trivial type of a known stride.
45+
TrivialStride,
46+
LastLayout = TrivialStride,
4547
};
4648

4749
#endif

include/swift/Demangling/TypeDecoder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ void decodeRequirement(NodePointer node,
430430
.Case("B", LayoutConstraintKind::BridgeObject)
431431
.Cases("E", "e", LayoutConstraintKind::TrivialOfExactSize)
432432
.Cases("M", "m", LayoutConstraintKind::TrivialOfAtMostSize)
433+
.Case("S", LayoutConstraintKind::TrivialStride)
433434
.Default(llvm::None);
434435

435436
if (!kind)
@@ -438,7 +439,8 @@ void decodeRequirement(NodePointer node,
438439
BuiltLayoutConstraint layout;
439440

440441
if (kind != LayoutConstraintKind::TrivialOfExactSize &&
441-
kind != LayoutConstraintKind::TrivialOfAtMostSize) {
442+
kind != LayoutConstraintKind::TrivialOfAtMostSize &&
443+
kind != LayoutConstraintKind::TrivialStride) {
442444
layout = Builder.getLayoutConstraint(*kind);
443445
} else {
444446
auto size = child->getChild(2)->getIndex();

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6024,7 +6024,8 @@ LayoutConstraint LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind
60246024
unsigned SizeInBits,
60256025
unsigned Alignment,
60266026
ASTContext &C) {
6027-
if (!LayoutConstraintInfo::isKnownSizeTrivial(Kind)) {
6027+
if (!LayoutConstraintInfo::isKnownSizeTrivial(Kind) &&
6028+
!LayoutConstraintInfo::isTrivialStride(Kind)) {
60286029
assert(SizeInBits == 0);
60296030
assert(Alignment == 0);
60306031
return getLayoutConstraint(Kind);

lib/AST/ASTMangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,6 +3804,9 @@ void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
38043804
case LayoutConstraintKind::BridgeObject:
38053805
appendOperatorParam("B");
38063806
break;
3807+
case LayoutConstraintKind::TrivialStride:
3808+
appendOperatorParam("S", Index(layout->getTrivialSizeInBits()));
3809+
break;
38073810
}
38083811
}
38093812

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7687,6 +7687,7 @@ void LayoutConstraintInfo::print(ASTPrinter &Printer,
76877687
return; // non-parameterized cases
76887688
case LayoutConstraintKind::TrivialOfAtMostSize:
76897689
case LayoutConstraintKind::TrivialOfExactSize:
7690+
case LayoutConstraintKind::TrivialStride:
76907691
Printer << "(";
76917692
Printer << SizeInBits;
76927693
if (Alignment)

lib/AST/GenericSignature.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,11 @@ GenericSignature GenericSignature::typeErased(ArrayRef<Type> typeErasedParams) c
527527
requirementsErased.push_back(
528528
Requirement(RequirementKind::SameType, req.getFirstType(),
529529
CanType(BuiltinIntegerType::get(bitWidth, C))));
530+
} else if (layout->isTrivialStride()) {
531+
unsigned bitWidth = layout->getTrivialStrideInBits();
532+
requirementsErased.push_back(
533+
Requirement(RequirementKind::SameType, req.getFirstType(),
534+
CanType(BuiltinIntegerType::get(bitWidth, C))));
530535
} else {
531536
requirementsErased.push_back(req);
532537
}

lib/AST/LayoutConstraint.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ LayoutConstraint getLayoutConstraint(Identifier ID, ASTContext &Ctx) {
5151
return LayoutConstraint::getLayoutConstraint(
5252
LayoutConstraintKind::BridgeObject, Ctx);
5353

54+
if (ID == Ctx.Id_TrivialStrideLayout)
55+
return LayoutConstraint::getLayoutConstraint(
56+
LayoutConstraintKind::TrivialStride, 0, 0, Ctx);
57+
5458
return LayoutConstraint::getLayoutConstraint(
5559
LayoutConstraintKind::UnknownLayout, Ctx);
5660
}
@@ -79,6 +83,8 @@ StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind, bool internal
7983
return "_Trivial";
8084
case LayoutConstraintKind::BridgeObject:
8185
return "_BridgeObject";
86+
case LayoutConstraintKind::TrivialStride:
87+
return "_TrivialStride";
8288
}
8389

8490
llvm_unreachable("Unhandled LayoutConstraintKind in switch.");
@@ -112,8 +118,9 @@ bool LayoutConstraintInfo::isAddressOnlyTrivial(LayoutConstraintKind Kind) {
112118
}
113119

114120
bool LayoutConstraintInfo::isTrivial(LayoutConstraintKind Kind) {
115-
return Kind > LayoutConstraintKind::UnknownLayout &&
116-
Kind <= LayoutConstraintKind::Trivial;
121+
return (Kind > LayoutConstraintKind::UnknownLayout &&
122+
Kind <= LayoutConstraintKind::Trivial) ||
123+
Kind == LayoutConstraintKind::TrivialStride;
117124
}
118125

119126
bool LayoutConstraintInfo::isRefCountedObject(LayoutConstraintKind Kind) {
@@ -150,6 +157,10 @@ bool LayoutConstraintInfo::isBridgeObject(LayoutConstraintKind Kind) {
150157
return Kind == LayoutConstraintKind::BridgeObject;
151158
}
152159

160+
bool LayoutConstraintInfo::isTrivialStride(LayoutConstraintKind Kind) {
161+
return Kind == LayoutConstraintKind::TrivialStride;
162+
}
163+
153164
SourceRange LayoutConstraintLoc::getSourceRange() const { return getLoc(); }
154165

155166
#define MERGE_LOOKUP(lhs, rhs) \
@@ -180,55 +191,64 @@ static LayoutConstraintKind mergeTable[unsigned(E(LastLayout)) +
180191
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
181192
E(/* Class */ Class), E(/* NativeClass */ NativeClass),
182193
E(/* RefCountedObject*/ RefCountedObject),
183-
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT},
194+
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT,
195+
MERGE_CONFLICT},
184196

185197
// Initialize the row for TrivialOfExactSize.
186198
{E(/* UnknownLayout */ TrivialOfExactSize),
187199
E(/* TrivialOfExactSize */ TrivialOfExactSize), MERGE_CONFLICT,
188200
E(/* Trivial */ TrivialOfExactSize), MERGE_CONFLICT, MERGE_CONFLICT,
189-
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
201+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
190202

191203
// Initialize the row for TrivialOfAtMostSize.
192204
{E(/* UnknownLayout */ TrivialOfAtMostSize), MERGE_CONFLICT,
193205
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize),
194206
E(/* Trivial */ TrivialOfAtMostSize), MERGE_CONFLICT, MERGE_CONFLICT,
195-
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
207+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
196208

197209
// Initialize the row for Trivial.
198210
{E(/* UnknownLayout */ Trivial),
199211
E(/* TrivialOfExactSize */ TrivialOfExactSize),
200212
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
201213
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
202-
MERGE_CONFLICT},
214+
MERGE_CONFLICT, MERGE_CONFLICT},
203215

204216
// Initialize the row for Class.
205217
{E(/* UnknownLayout*/ Class), MERGE_CONFLICT, MERGE_CONFLICT,
206218
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
207219
E(/* RefCountedObject */ Class),
208-
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT},
220+
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT,
221+
MERGE_CONFLICT},
209222

210223
// Initialize the row for NativeClass.
211224
{E(/* UnknownLayout */ NativeClass), MERGE_CONFLICT, MERGE_CONFLICT,
212225
MERGE_CONFLICT, E(/* Class */ NativeClass),
213226
E(/* NativeClass */ NativeClass), E(/* RefCountedObject */ NativeClass),
214-
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT},
227+
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT,
228+
MERGE_CONFLICT},
215229

216230
// Initialize the row for RefCountedObject.
217231
{E(/* UnknownLayout */ RefCountedObject), MERGE_CONFLICT, MERGE_CONFLICT,
218232
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
219233
E(/* RefCountedObject */ RefCountedObject),
220-
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT},
234+
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT,
235+
MERGE_CONFLICT},
221236

222237
// Initialize the row for NativeRefCountedObject.
223238
{E(/* UnknownLayout */ NativeRefCountedObject), MERGE_CONFLICT,
224239
MERGE_CONFLICT, MERGE_CONFLICT, E(/* Class */ NativeClass),
225240
E(/* NativeClass */ NativeClass),
226241
E(/* RefCountedObject */ NativeRefCountedObject),
227-
E(/* NativeRefCountedObject*/ NativeRefCountedObject), MERGE_CONFLICT},
242+
E(/* NativeRefCountedObject*/ NativeRefCountedObject), MERGE_CONFLICT,
243+
MERGE_CONFLICT},
228244

229245
{E(BridgeObject), MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
230246
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
231-
E(/*BridgeObject*/ BridgeObject)},
247+
E(/*BridgeObject*/ BridgeObject), MERGE_CONFLICT},
248+
249+
{E(TrivialStride), MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
250+
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
251+
MERGE_CONFLICT, E(/*TrivialStride*/ TrivialStride)},
232252
};
233253

234254
#undef E
@@ -324,6 +344,7 @@ LayoutConstraint::merge(LayoutConstraint Other) {
324344
LayoutConstraint
325345
LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind) {
326346
assert(!LayoutConstraintInfo::isKnownSizeTrivial(Kind));
347+
assert(!LayoutConstraintInfo::isTrivialStride(Kind));
327348
switch(Kind) {
328349
case LayoutConstraintKind::Trivial:
329350
return LayoutConstraint(&LayoutConstraintInfo::TrivialConstraintInfo);
@@ -343,6 +364,7 @@ LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind) {
343364
return LayoutConstraint(&LayoutConstraintInfo::BridgeObjectConstraintInfo);
344365
case LayoutConstraintKind::TrivialOfAtMostSize:
345366
case LayoutConstraintKind::TrivialOfExactSize:
367+
case LayoutConstraintKind::TrivialStride:
346368
llvm_unreachable("Wrong layout constraint kind");
347369
}
348370
llvm_unreachable("unhandled kind");

lib/Demangling/Demangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4052,6 +4052,11 @@ NodePointer Demangler::demangleGenericRequirement() {
40524052
if (!size)
40534053
return nullptr;
40544054
name = "m";
4055+
} else if (c == 'S') {
4056+
size = demangleIndexAsNode();
4057+
if (!size)
4058+
return nullptr;
4059+
name = "S";
40554060
} else {
40564061
// Unknown layout constraint.
40574062
return nullptr;

lib/Demangling/OldDemangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,11 @@ class OldDemangler {
16641664
if (!demangleNatural(size, depth + 1))
16651665
return nullptr;
16661666
name = "m";
1667+
} else if (Mangled.nextIf('S')) {
1668+
kind = Node::Kind::Identifier;
1669+
if (!demangleNatural(size, depth + 1))
1670+
return nullptr;
1671+
name = "S";
16671672
} else {
16681673
return nullptr;
16691674
}

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,7 @@ class SubstFunctionTypePatternVisitor
22392239
case LayoutConstraintKind::RefCountedObject:
22402240
case LayoutConstraintKind::TrivialOfAtMostSize:
22412241
case LayoutConstraintKind::BridgeObject:
2242+
case LayoutConstraintKind::TrivialStride:
22422243
break;
22432244

22442245
case LayoutConstraintKind::UnknownLayout:

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3003,7 +3003,7 @@ bool usePrespecialized(
30033003

30043004
if (!erased || !layout ||
30053005
(!layout->isClass() && !layout->isBridgeObject() &&
3006-
!layout->isFixedSizeTrivial())) {
3006+
!layout->isFixedSizeTrivial() && !layout->isTrivialStride())) {
30073007
newSubs.push_back(entry.value());
30083008
continue;
30093009
}
@@ -3036,6 +3036,23 @@ bool usePrespecialized(
30363036
BuiltinIntegerType::get(layout->getTrivialSizeInBits(),
30373037
genericParam->getASTContext())));
30383038
}
3039+
} else if (layout->isTrivialStride() && lowered.isTrivial(refF)) {
3040+
auto *IGM = funcBuilder.getIRGenModule();
3041+
auto &ti = IGM->getTypeInfo(lowered);
3042+
auto *typeLayout = ti.buildTypeLayoutEntry(*IGM, lowered, false);
3043+
auto fixedSize = typeLayout->fixedSize(*IGM);
3044+
if (fixedSize) {
3045+
auto stride = fixedSize->roundUpToAlignment(
3046+
*typeLayout->fixedAlignment(*IGM));
3047+
if (stride.isZero())
3048+
stride = irgen::Size(1);
3049+
3050+
if (stride.getValueInBits() == layout->getTrivialStrideInBits()) {
3051+
newSubs.push_back(CanType(
3052+
BuiltinIntegerType::get(layout->getTrivialStrideInBits(),
3053+
genericParam->getASTContext())));
3054+
}
3055+
}
30393056
} else {
30403057
// no match
30413058
break;

lib/Serialization/Deserialization.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ getActualLayoutConstraintKind(uint64_t rawKind) {
11851185
CASE(NativeClass)
11861186
CASE(UnknownLayout)
11871187
CASE(BridgeObject)
1188+
CASE(TrivialStride)
11881189
}
11891190
#undef CASE
11901191

@@ -1244,7 +1245,8 @@ llvm::Error ModuleFile::deserializeGenericRequirementsChecked(
12441245
ASTContext &ctx = getContext();
12451246
LayoutConstraint layout;
12461247
if (kind != LayoutConstraintKind::TrivialOfAtMostSize &&
1247-
kind != LayoutConstraintKind::TrivialOfExactSize)
1248+
kind != LayoutConstraintKind::TrivialOfExactSize &&
1249+
kind != LayoutConstraintKind::TrivialStride)
12481250
layout = LayoutConstraint::getLayoutConstraint(kind, ctx);
12491251
else
12501252
layout =

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 824; // LayoutRequirementKindField
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 825; // TrivialStride
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -484,6 +484,7 @@ enum LayoutRequirementKind : uint8_t {
484484
Class = 6,
485485
NativeClass = 7,
486486
BridgeObject = 8,
487+
TrivialStride = 9,
487488
};
488489
using LayoutRequirementKindField = BCFixed<4>;
489490

lib/Serialization/Serialization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,8 @@ void Serializer::serializeGenericRequirements(
14801480
if (layout->isKnownSizeTrivial()) {
14811481
size = layout->getTrivialSizeInBits();
14821482
alignment = layout->getAlignmentInBits();
1483+
} else if (layout->isTrivialStride()) {
1484+
size = layout->getTrivialStrideInBits();
14831485
}
14841486
LayoutRequirementKind rawKind = LayoutRequirementKind::UnknownLayout;
14851487
switch (layout->getKind()) {
@@ -1510,6 +1512,9 @@ void Serializer::serializeGenericRequirements(
15101512
case LayoutConstraintKind::BridgeObject:
15111513
rawKind = LayoutRequirementKind::BridgeObject;
15121514
break;
1515+
case LayoutConstraintKind::TrivialStride:
1516+
rawKind = LayoutRequirementKind::TrivialStride;
1517+
break;
15131518
}
15141519
scratch.push_back(rawKind);
15151520
scratch.push_back(addTypeRef(req.getFirstType()));

test/SILOptimizer/Inputs/pre_specialized_module_layouts.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class SomeClass {
1212
@_specialize(exported: true, where @_noMetadata T : _Class)
1313
@_specialize(exported: true, where @_noMetadata T : _BridgeObject)
1414
@_specialize(exported: true, where @_noMetadata T : _Trivial(64))
15+
@_specialize(exported: true, where @_noMetadata T : _TrivialStride(128))
1516
@_specialize(exported: true, availability: macOS 10.50, *; where T == SomeData)
1617
public func publicPrespecialized<T>(_ t: T) {
1718
}

0 commit comments

Comments
 (0)