Skip to content

Commit f2c4250

Browse files
authored
Merge pull request swiftlang#20345 from slavapestov/reflection-bitwise-takable
Reflection: Compute if types are bitwise takable
2 parents e5c1567 + 00c1279 commit f2c4250

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1307
-987
lines changed

include/swift/Reflection/Records.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,23 @@ class BuiltinTypeDescriptor {
402402

403403
public:
404404
uint32_t Size;
405-
uint32_t Alignment;
405+
406+
// - Least significant 16 bits are the alignment.
407+
// - Bit 16 is 'bitwise takable'.
408+
// - Remaining bits are reserved.
409+
uint32_t AlignmentAndFlags;
410+
406411
uint32_t Stride;
407412
uint32_t NumExtraInhabitants;
408413

414+
bool isBitwiseTakable() const {
415+
return (AlignmentAndFlags >> 16) & 1;
416+
}
417+
418+
uint32_t getAlignment() const {
419+
return AlignmentAndFlags & 0xffff;
420+
}
421+
409422
bool hasMangledTypeName() const {
410423
return TypeName;
411424
}

include/swift/Reflection/ReflectionContext.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,17 @@ class ReflectionContext
541541
return nullptr;
542542

543543
// Initialize the builder.
544-
Builder.addField(*OffsetToFirstCapture, sizeof(StoredPointer),
545-
/*numExtraInhabitants=*/0);
544+
Builder.addField(*OffsetToFirstCapture,
545+
/*alignment=*/sizeof(StoredPointer),
546+
/*numExtraInhabitants=*/0,
547+
/*bitwiseTakable=*/true);
546548

547549
// Skip the closure's necessary bindings struct, if it's present.
548550
auto SizeOfNecessaryBindings = Info.NumBindings * sizeof(StoredPointer);
549-
Builder.addField(SizeOfNecessaryBindings, sizeof(StoredPointer),
550-
/*numExtraInhabitants=*/0);
551+
Builder.addField(/*size=*/SizeOfNecessaryBindings,
552+
/*alignment=*/sizeof(StoredPointer),
553+
/*numExtraInhabitants=*/0,
554+
/*bitwiseTakable=*/true);
551555

552556
// FIXME: should be unordered_set but I'm too lazy to write a hash
553557
// functor

include/swift/Reflection/TypeLowering.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,16 @@ enum class TypeInfoKind : unsigned {
110110
class TypeInfo {
111111
TypeInfoKind Kind;
112112
unsigned Size, Alignment, Stride, NumExtraInhabitants;
113+
bool BitwiseTakable;
113114

114115
public:
115116
TypeInfo(TypeInfoKind Kind,
116117
unsigned Size, unsigned Alignment,
117-
unsigned Stride, unsigned NumExtraInhabitants)
118+
unsigned Stride, unsigned NumExtraInhabitants,
119+
bool BitwiseTakable)
118120
: Kind(Kind), Size(Size), Alignment(Alignment), Stride(Stride),
119-
NumExtraInhabitants(NumExtraInhabitants) {
121+
NumExtraInhabitants(NumExtraInhabitants),
122+
BitwiseTakable(BitwiseTakable) {
120123
assert(Alignment > 0);
121124
}
122125

@@ -126,6 +129,7 @@ class TypeInfo {
126129
unsigned getAlignment() const { return Alignment; }
127130
unsigned getStride() const { return Stride; }
128131
unsigned getNumExtraInhabitants() const { return NumExtraInhabitants; }
132+
bool isBitwiseTakable() const { return BitwiseTakable; }
129133

130134
void dump() const;
131135
void dump(std::ostream &OS, unsigned Indent = 0) const;
@@ -162,9 +166,10 @@ class RecordTypeInfo : public TypeInfo {
162166
public:
163167
RecordTypeInfo(unsigned Size, unsigned Alignment,
164168
unsigned Stride, unsigned NumExtraInhabitants,
169+
bool BitwiseTakable,
165170
RecordKind SubKind, const std::vector<FieldInfo> &Fields)
166171
: TypeInfo(TypeInfoKind::Record, Size, Alignment, Stride,
167-
NumExtraInhabitants),
172+
NumExtraInhabitants, BitwiseTakable),
168173
SubKind(SubKind), Fields(Fields) {}
169174

170175
RecordKind getRecordKind() const { return SubKind; }
@@ -185,9 +190,10 @@ class ReferenceTypeInfo : public TypeInfo {
185190
public:
186191
ReferenceTypeInfo(unsigned Size, unsigned Alignment,
187192
unsigned Stride, unsigned NumExtraInhabitants,
188-
ReferenceKind SubKind, ReferenceCounting Refcounting)
193+
bool BitwiseTakable, ReferenceKind SubKind,
194+
ReferenceCounting Refcounting)
189195
: TypeInfo(TypeInfoKind::Reference, Size, Alignment, Stride,
190-
NumExtraInhabitants),
196+
NumExtraInhabitants, BitwiseTakable),
191197
SubKind(SubKind), Refcounting(Refcounting) {}
192198

193199
ReferenceKind getReferenceKind() const {
@@ -286,6 +292,7 @@ class TypeConverter {
286292
class RecordTypeInfoBuilder {
287293
TypeConverter &TC;
288294
unsigned Size, Alignment, NumExtraInhabitants;
295+
bool BitwiseTakable;
289296
RecordKind Kind;
290297
std::vector<FieldInfo> Fields;
291298
bool Empty;
@@ -294,14 +301,15 @@ class RecordTypeInfoBuilder {
294301
public:
295302
RecordTypeInfoBuilder(TypeConverter &TC, RecordKind Kind)
296303
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
297-
Kind(Kind), Empty(true), Invalid(false) {}
304+
BitwiseTakable(true), Kind(Kind), Empty(true), Invalid(false) {}
298305

299306
bool isInvalid() const {
300307
return Invalid;
301308
}
302309

303310
unsigned addField(unsigned fieldSize, unsigned fieldAlignment,
304-
unsigned numExtraInhabitants);
311+
unsigned numExtraInhabitants,
312+
bool bitwiseTakable);
305313

306314
// Add a field of a record type, such as a struct.
307315
void addField(const std::string &Name, const TypeRef *TR);

lib/IRGen/GenReflection.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,11 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
426426
}
427427

428428
void layoutProtocol() {
429-
auto protocolDecl = cast<ProtocolDecl>(NTD);
429+
auto PD = cast<ProtocolDecl>(NTD);
430430
FieldDescriptorKind Kind;
431-
if (protocolDecl->isObjC())
431+
if (PD->isObjC())
432432
Kind = FieldDescriptorKind::ObjCProtocol;
433-
else if (protocolDecl->requiresClass())
433+
else if (PD->requiresClass())
434434
Kind = FieldDescriptorKind::ClassProtocol;
435435
else
436436
Kind = FieldDescriptorKind::Protocol;
@@ -446,8 +446,11 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
446446
addNominalRef(NTD);
447447

448448
auto *CD = dyn_cast<ClassDecl>(NTD);
449+
auto *PD = dyn_cast<ProtocolDecl>(NTD);
449450
if (CD && CD->getSuperclass()) {
450451
addTypeRef(CD->getSuperclass()->getCanonicalType());
452+
} else if (PD && PD->getDeclaredType()->getSuperclass()) {
453+
addTypeRef(PD->getDeclaredType()->getSuperclass()->getCanonicalType());
451454
} else {
452455
B.addInt32(0);
453456
}
@@ -515,7 +518,13 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
515518
addTypeRef(type);
516519

517520
B.addInt32(ti->getFixedSize().getValue());
518-
B.addInt32(ti->getFixedAlignment().getValue());
521+
522+
auto alignment = ti->getFixedAlignment().getValue();
523+
unsigned bitwiseTakable =
524+
(ti->isBitwiseTakable(ResilienceExpansion::Minimal) == IsBitwiseTakable
525+
? 1 : 0);
526+
B.addInt32(alignment | (bitwiseTakable << 16));
527+
519528
B.addInt32(ti->getFixedStride().getValue());
520529
B.addInt32(ti->getFixedExtraInhabitantCount(IGM));
521530
}

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class PrintTypeInfo {
7777
printField("alignment", TI.getAlignment());
7878
printField("stride", TI.getStride());
7979
printField("num_extra_inhabitants", TI.getNumExtraInhabitants());
80+
printField("bitwise_takable", TI.isBitwiseTakable());
8081
}
8182

8283
void printFields(const RecordTypeInfo &TI) {
@@ -190,8 +191,12 @@ void TypeInfo::dump(std::ostream &OS, unsigned Indent) const {
190191
}
191192

192193
BuiltinTypeInfo::BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor)
193-
: TypeInfo(TypeInfoKind::Builtin, descriptor->Size, descriptor->Alignment,
194-
descriptor->Stride, descriptor->NumExtraInhabitants),
194+
: TypeInfo(TypeInfoKind::Builtin,
195+
descriptor->Size,
196+
descriptor->getAlignment(),
197+
descriptor->Stride,
198+
descriptor->NumExtraInhabitants,
199+
descriptor->isBitwiseTakable()),
195200
Name(descriptor->getMangledTypeName(0)) {}
196201

197202
/// Utility class for building values that contain witness tables.
@@ -263,6 +268,29 @@ class ExistentialTypeInfoBuilder {
263268
case FieldDescriptorKind::ClassProtocol:
264269
Representation = ExistentialTypeRepresentation::Class;
265270
WitnessTableCount++;
271+
272+
if (auto *Superclass = TC.getBuilder().lookupSuperclass(P)) {
273+
auto *SuperclassTI = TC.getTypeInfo(Superclass);
274+
if (SuperclassTI == nullptr) {
275+
DEBUG_LOG(std::cerr << "No TypeInfo for superclass: ";
276+
Superclass->dump());
277+
Invalid = true;
278+
continue;
279+
}
280+
281+
if (!isa<ReferenceTypeInfo>(SuperclassTI)) {
282+
DEBUG_LOG(std::cerr << "Superclass not a reference type: ";
283+
SuperclassTI->dump());
284+
Invalid = true;
285+
continue;
286+
}
287+
288+
if (cast<ReferenceTypeInfo>(SuperclassTI)->getReferenceCounting()
289+
== ReferenceCounting::Native) {
290+
Refcounting = ReferenceCounting::Native;
291+
}
292+
}
293+
266294
continue;
267295
case FieldDescriptorKind::Protocol:
268296
WitnessTableCount++;
@@ -397,9 +425,12 @@ class ExistentialTypeInfoBuilder {
397425

398426
// Non-class existentials consist of a three-word buffer,
399427
// value metadata, and finally zero or more witness tables.
428+
// The buffer is always bitwise takable, since non-bitwise
429+
// takable payloads are stored out of line.
400430
builder.addField(TI->getSize() * 3,
401431
TI->getAlignment(),
402-
/*numExtraInhabitants=*/0);
432+
/*numExtraInhabitants=*/0,
433+
/*bitwiseTakable=*/true);
403434
builder.addField("metadata", TC.getAnyMetatypeTypeRef());
404435
break;
405436
}
@@ -441,7 +472,8 @@ class ExistentialTypeInfoBuilder {
441472

442473
unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize,
443474
unsigned fieldAlignment,
444-
unsigned numExtraInhabitants) {
475+
unsigned numExtraInhabitants,
476+
bool bitwiseTakable) {
445477
assert(fieldAlignment > 0);
446478

447479
// Align the current size appropriately
@@ -456,6 +488,9 @@ unsigned RecordTypeInfoBuilder::addField(unsigned fieldSize,
456488
// Update the aggregate alignment
457489
Alignment = std::max(Alignment, fieldAlignment);
458490

491+
// The aggregate is bitwise takable if all elements are.
492+
BitwiseTakable &= bitwiseTakable;
493+
459494
switch (Kind) {
460495
// The extra inhabitants of a struct or tuple are the same as the extra
461496
// inhabitants of the field that has the most.
@@ -500,7 +535,8 @@ void RecordTypeInfoBuilder::addField(const std::string &Name,
500535

501536
unsigned offset = addField(TI->getSize(),
502537
TI->getAlignment(),
503-
TI->getNumExtraInhabitants());
538+
TI->getNumExtraInhabitants(),
539+
TI->isBitwiseTakable());
504540
Fields.push_back({Name, offset, TR, *TI});
505541
}
506542

@@ -515,7 +551,8 @@ const RecordTypeInfo *RecordTypeInfoBuilder::build() {
515551

516552
return TC.makeTypeInfo<RecordTypeInfo>(
517553
Size, Alignment, Stride,
518-
NumExtraInhabitants, Kind, Fields);
554+
NumExtraInhabitants, BitwiseTakable,
555+
Kind, Fields);
519556
}
520557

521558
const ReferenceTypeInfo *
@@ -548,13 +585,28 @@ TypeConverter::getReferenceTypeInfo(ReferenceKind Kind,
548585
}
549586

550587
unsigned numExtraInhabitants = BuiltinTI->NumExtraInhabitants;
551-
if (Kind == ReferenceKind::Weak)
588+
bool bitwiseTakable = true;
589+
590+
switch (Kind) {
591+
case ReferenceKind::Strong:
592+
break;
593+
case ReferenceKind::Weak:
552594
numExtraInhabitants = 0;
595+
bitwiseTakable = false;
596+
break;
597+
case ReferenceKind::Unowned:
598+
if (Refcounting == ReferenceCounting::Unknown)
599+
bitwiseTakable = false;
600+
break;
601+
case ReferenceKind::Unmanaged:
602+
break;
603+
}
553604

554605
auto *TI = makeTypeInfo<ReferenceTypeInfo>(BuiltinTI->Size,
555-
BuiltinTI->Alignment,
606+
BuiltinTI->getAlignment(),
556607
BuiltinTI->Stride,
557608
numExtraInhabitants,
609+
bitwiseTakable,
558610
Kind, Refcounting);
559611
ReferenceCache[key] = TI;
560612
return TI;
@@ -619,7 +671,12 @@ const TypeInfo *TypeConverter::getEmptyTypeInfo() {
619671
if (EmptyTI != nullptr)
620672
return EmptyTI;
621673

622-
EmptyTI = makeTypeInfo<TypeInfo>(TypeInfoKind::Builtin, 0, 1, 1, 0);
674+
EmptyTI = makeTypeInfo<TypeInfo>(TypeInfoKind::Builtin,
675+
/*Size=*/0,
676+
/*Alignment=*/1,
677+
/*Stride=*/1,
678+
/*ExtraInhabitants=*/0,
679+
/*BitwiseTakable=*/true);
623680
return EmptyTI;
624681
}
625682

@@ -919,6 +976,7 @@ static unsigned getNumTagBytes(size_t size, unsigned emptyCases,
919976
class EnumTypeInfoBuilder {
920977
TypeConverter &TC;
921978
unsigned Size, Alignment, NumExtraInhabitants;
979+
bool BitwiseTakable;
922980
RecordKind Kind;
923981
std::vector<FieldInfo> Cases;
924982
bool Invalid;
@@ -942,14 +1000,15 @@ class EnumTypeInfoBuilder {
9421000

9431001
Size = std::max(Size, TI->getSize());
9441002
Alignment = std::max(Alignment, TI->getAlignment());
1003+
BitwiseTakable &= TI->isBitwiseTakable();
9451004

9461005
Cases.push_back({Name, /*offset=*/0, TR, *TI});
9471006
}
9481007

9491008
public:
9501009
EnumTypeInfoBuilder(TypeConverter &TC)
9511010
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
952-
Kind(RecordKind::Invalid), Invalid(false) {}
1011+
BitwiseTakable(true), Kind(RecordKind::Invalid), Invalid(false) {}
9531012

9541013
const TypeInfo *
9551014
build(const TypeRef *TR,
@@ -1028,8 +1087,9 @@ class EnumTypeInfoBuilder {
10281087
auto *FixedDescriptor = TC.getBuilder().getBuiltinTypeInfo(TR);
10291088
if (FixedDescriptor) {
10301089
Size = FixedDescriptor->Size;
1031-
Alignment = FixedDescriptor->Alignment;
1090+
Alignment = FixedDescriptor->getAlignment();
10321091
NumExtraInhabitants = FixedDescriptor->NumExtraInhabitants;
1092+
BitwiseTakable = FixedDescriptor->isBitwiseTakable();
10331093
} else {
10341094
// Dynamic multi-payload enums do not have extra inhabitants
10351095
NumExtraInhabitants = 0;
@@ -1052,7 +1112,8 @@ class EnumTypeInfoBuilder {
10521112

10531113
return TC.makeTypeInfo<RecordTypeInfo>(
10541114
Size, Alignment, Stride,
1055-
NumExtraInhabitants, Kind, Cases);
1115+
NumExtraInhabitants, BitwiseTakable,
1116+
Kind, Cases);
10561117
}
10571118
};
10581119

@@ -1263,10 +1324,12 @@ class LowerType
12631324
// Destructure the existential and replace the "object"
12641325
// field with the right reference kind.
12651326
} else if (SubKind == RecordKind::ClassExistential) {
1327+
bool BitwiseTakable = RecordTI->isBitwiseTakable();
12661328
std::vector<FieldInfo> Fields;
12671329
for (auto &Field : RecordTI->getFields()) {
12681330
if (Field.Name == "object") {
12691331
auto *FieldTI = rebuildStorageTypeInfo(&Field.TI, Kind);
1332+
BitwiseTakable &= FieldTI->isBitwiseTakable();
12701333
Fields.push_back({Field.Name, Field.Offset, Field.TR, *FieldTI});
12711334
continue;
12721335
}
@@ -1278,6 +1341,7 @@ class LowerType
12781341
RecordTI->getAlignment(),
12791342
RecordTI->getStride(),
12801343
RecordTI->getNumExtraInhabitants(),
1344+
BitwiseTakable,
12811345
SubKind, Fields);
12821346
}
12831347
}
@@ -1354,7 +1418,10 @@ const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR,
13541418

13551419
// Start layout from the given instance start offset. This should
13561420
// be the superclass instance size.
1357-
builder.addField(start, 1, /*numExtraInhabitants=*/0);
1421+
builder.addField(/*size=*/start,
1422+
/*alignment=*/1,
1423+
/*numExtraInhabitants=*/0,
1424+
/*bitwiseTakable=*/true);
13581425

13591426
for (auto Field : Fields)
13601427
builder.addField(Field.Name, Field.TR);

0 commit comments

Comments
 (0)