Skip to content

Commit 6abaf21

Browse files
authored
Merge pull request #70998 from xedin/bitfield-for-protocol-conformance-type
[AST] Augment `ProtocolConformance` and sublcasses to use bitfields for its auxiliary information
2 parents f7dcecd + 60badd6 commit 6abaf21

File tree

3 files changed

+136
-89
lines changed

3 files changed

+136
-89
lines changed

include/swift/AST/DeclContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ enum class ConformanceEntryKind : unsigned {
158158

159159
/// Implied by an explicitly-specified conformance.
160160
Implied,
161+
162+
Last_Kind = Implied
161163
};
162164

163165
/// Describes the kind of conformance lookup desired.

include/swift/AST/ProtocolConformance.h

Lines changed: 129 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/Witness.h"
2525
#include "swift/Basic/Compiler.h"
2626
#include "swift/Basic/Debug.h"
27+
#include "swift/Basic/InlineBitfield.h"
2728
#include "llvm/ADT/ArrayRef.h"
2829
#include "llvm/ADT/DenseMap.h"
2930
#include "llvm/ADT/FoldingSet.h"
@@ -55,7 +56,7 @@ typedef llvm::DenseMap<AssociatedTypeDecl *, TypeWitnessAndDecl>
5556

5657
/// Describes the kind of protocol conformance structure used to encode
5758
/// conformance.
58-
enum class ProtocolConformanceKind {
59+
enum class ProtocolConformanceKind : unsigned {
5960
/// "Normal" conformance of a (possibly generic) nominal type, which
6061
/// contains complete mappings.
6162
Normal,
@@ -69,20 +70,54 @@ enum class ProtocolConformanceKind {
6970
Inherited,
7071
/// Builtin conformances are special conformances that the runtime handles
7172
/// and isn't implemented directly in Swift.
72-
Builtin
73+
Builtin,
74+
75+
Last_Kind = Builtin
76+
};
77+
enum : unsigned {
78+
NumProtocolConformanceKindBits =
79+
countBitsUsed(static_cast<unsigned>(ProtocolConformanceKind::Last_Kind))
7380
};
7481

7582
/// Describes the state of a protocol conformance, which may be complete,
7683
/// incomplete, or currently being checked.
7784
enum class ProtocolConformanceState {
7885
/// The conformance has been fully checked.
79-
Complete,
86+
Complete = 0,
8087
/// The conformance is known but is not yet complete.
8188
Incomplete,
8289
/// The conformance's type witnesses are currently being resolved.
8390
CheckingTypeWitnesses,
8491
/// The conformance is being checked.
8592
Checking,
93+
94+
Last_State = Checking
95+
};
96+
97+
/// Describes the kind of a builtin conformance.
98+
enum class BuiltinConformanceKind {
99+
// A builtin conformance that has been synthesized by the implementation.
100+
Synthesized = 0,
101+
// A missing conformance that we have nonetheless synthesized so that
102+
// we can diagnose it later.
103+
Missing,
104+
105+
Last_Kind = Missing
106+
};
107+
108+
enum : unsigned {
109+
NumProtocolConformanceStateBits =
110+
countBitsUsed(static_cast<unsigned>(ProtocolConformanceState::Last_State))
111+
};
112+
113+
enum : unsigned {
114+
NumConformanceEntryKindBits =
115+
countBitsUsed(static_cast<unsigned>(ConformanceEntryKind::Last_Kind))
116+
};
117+
118+
enum : unsigned {
119+
NumBuiltinConformanceKindBits =
120+
countBitsUsed(static_cast<unsigned>(BuiltinConformanceKind::Last_Kind))
86121
};
87122

88123
/// Describes how a particular type conforms to a given protocol,
@@ -93,20 +128,73 @@ enum class ProtocolConformanceState {
93128
/// for the various kinds of conformance (normal, specialized, inherited).
94129
class alignas(1 << DeclAlignInBits) ProtocolConformance
95130
: public ASTAllocated<ProtocolConformance> {
96-
/// The kind of protocol conformance.
97-
ProtocolConformanceKind Kind;
98-
99131
/// The type that conforms to the protocol, in the context of the
100132
/// conformance definition.
101133
Type ConformingType;
102134

103135
protected:
136+
// clang-format off
137+
//
138+
// We format these different than clang-format wishes us to... so turn if off
139+
// for the inline bitfields.
140+
union { uint64_t OpaqueBits;
141+
142+
SWIFT_INLINE_BITFIELD_BASE(ProtocolConformance,
143+
bitmax(NumProtocolConformanceKindBits, 8),
144+
/// The kind of protocol conformance.
145+
Kind : bitmax(NumProtocolConformanceKindBits, 8)
146+
);
147+
148+
SWIFT_INLINE_BITFIELD_EMPTY(RootProtocolConformance, ProtocolConformance);
149+
150+
SWIFT_INLINE_BITFIELD_FULL(NormalProtocolConformance, RootProtocolConformance,
151+
1+1+1+1+bitmax(NumProtocolConformanceStateBits,8)+
152+
bitmax(NumConformanceEntryKindBits,8),
153+
/// Indicates whether the conformance is invalid.
154+
IsInvalid : 1,
155+
/// The conformance was labeled with @unchecked.
156+
IsUnchecked : 1,
157+
/// The conformance was labeled with @preconcurrency.
158+
IsPreconcurrency : 1,
159+
/// We have allocated the AssociatedConformances array (but not necessarily
160+
/// populated any of its elements).
161+
HasComputedAssociatedConformances : 1,
162+
163+
: NumPadBits,
164+
165+
/// The current state of the conformance.
166+
State : bitmax(NumProtocolConformanceStateBits, 8),
167+
/// The reason that this conformance exists.
168+
///
169+
/// Either Explicit (e.g. 'struct Foo: Protocol {}' or 'extension Foo:
170+
/// Protocol {}'), Synthesized (e.g. RawRepresentable for 'enum Foo: Int {}')
171+
/// or Implied (e.g. 'Foo : Protocol' in 'protocol Other: Protocol {} struct
172+
/// Foo: Other {}'). In only the latter case, the conformance is non-null and
173+
/// points to the conformance that implies this one.
174+
///
175+
/// This should never be Inherited: that is handled by
176+
/// InheritedProtocolConformance.
177+
SourceKind : bitmax(NumConformanceEntryKindBits, 8)
178+
);
179+
180+
SWIFT_INLINE_BITFIELD(BuiltinProtocolConformance, RootProtocolConformance,
181+
bitmax(NumBuiltinConformanceKindBits, 8),
182+
/// The kind of the builtin conformance
183+
Kind: bitmax(NumBuiltinConformanceKindBits, 8)
184+
);
185+
} Bits;
186+
// clang-format on
187+
104188
ProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
105-
: Kind(kind), ConformingType(conformingType) {}
189+
: ConformingType(conformingType) {
190+
Bits.ProtocolConformance.Kind = unsigned(kind);
191+
}
106192

107193
public:
108194
/// Determine the kind of protocol conformance.
109-
ProtocolConformanceKind getKind() const { return Kind; }
195+
ProtocolConformanceKind getKind() const {
196+
return static_cast<ProtocolConformanceKind>(Bits.ProtocolConformance.Kind);
197+
}
110198

111199
/// Get the conforming type.
112200
Type getType() const { return ConformingType; }
@@ -435,49 +523,17 @@ class NormalProtocolConformance : public RootProtocolConformance,
435523
friend class ValueWitnessRequest;
436524
friend class TypeWitnessRequest;
437525

438-
/// The protocol being conformed to and its current state.
439-
llvm::PointerIntPair<ProtocolDecl *, 2, ProtocolConformanceState>
440-
ProtocolAndState;
526+
/// The protocol being conformed to.
527+
ProtocolDecl *Protocol;
441528

442529
/// The location of this protocol conformance in the source.
443530
SourceLoc Loc;
444531

445-
// Flag bits used in ContextAndBits.
446-
enum {
447-
/// The conformance was labeled with @unchecked.
448-
UncheckedFlag = 0x01,
449-
450-
/// The conformance was labeled with @preconcurrency.
451-
PreconcurrencyFlag = 0x02,
452-
453-
/// We have allocated the AssociatedConformances array (but not necessarily
454-
/// populated any of its elements).
455-
HasComputedAssociatedConformancesFlag = 0x04,
456-
};
457-
458532
/// The declaration context containing the ExtensionDecl or
459533
/// NominalTypeDecl that declared the conformance.
460-
///
461-
/// Also stores the "unchecked", "preconcurrency" and "has computed associated
462-
/// conformances" bits.
463-
llvm::PointerIntPair<DeclContext *, 3, unsigned> ContextAndBits;
534+
DeclContext *Context;
464535

465-
/// Indicates whether the conformance is invalid.
466-
bool Invalid : 1;
467-
468-
/// The reason that this conformance exists.
469-
///
470-
/// Either Explicit (e.g. 'struct Foo: Protocol {}' or 'extension Foo:
471-
/// Protocol {}'), Synthesized (e.g. RawRepresentable for 'enum Foo: Int {}')
472-
/// or Implied (e.g. 'Foo : Protocol' in 'protocol Other: Protocol {} struct
473-
/// Foo: Other {}'). In only the latter case, the conformance is non-null and
474-
/// points to the conformance that implies this one.
475-
///
476-
/// This should never be Inherited: that is handled by
477-
/// InheritedProtocolConformance.
478-
llvm::PointerIntPair<NormalProtocolConformance *, 3, ConformanceEntryKind>
479-
SourceKindAndImplyingConformance = {nullptr,
480-
ConformanceEntryKind::Explicit};
536+
NormalProtocolConformance *ImplyingConformance = nullptr;
481537

482538
/// The mapping of individual requirements in the protocol over to
483539
/// the declarations that satisfy those requirements.
@@ -508,25 +564,27 @@ class NormalProtocolConformance : public RootProtocolConformance,
508564
bool isPreconcurrency)
509565
: RootProtocolConformance(ProtocolConformanceKind::Normal,
510566
conformingType),
511-
ProtocolAndState(protocol, state), Loc(loc),
512-
ContextAndBits(dc, ((isUnchecked ? UncheckedFlag : 0) |
513-
(isPreconcurrency ? PreconcurrencyFlag : 0))),
514-
Invalid(false) {
567+
Protocol(protocol), Loc(loc), Context(dc) {
515568
assert(!conformingType->hasArchetype() &&
516569
"ProtocolConformances should store interface types");
570+
setState(state);
571+
Bits.NormalProtocolConformance.IsInvalid = false;
572+
Bits.NormalProtocolConformance.IsUnchecked = isUnchecked;
573+
Bits.NormalProtocolConformance.IsPreconcurrency = isPreconcurrency;
574+
Bits.NormalProtocolConformance.HasComputedAssociatedConformances = false;
575+
Bits.NormalProtocolConformance.SourceKind =
576+
unsigned(ConformanceEntryKind::Explicit);
517577
}
518578

519579
/// Get the protocol being conformed to.
520-
ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); }
580+
ProtocolDecl *getProtocol() const { return Protocol; }
521581

522582
/// Retrieve the location of this
523583
SourceLoc getLoc() const { return Loc; }
524584

525585
/// Get the declaration context that contains the conforming extension or
526586
/// nominal type declaration.
527-
DeclContext *getDeclContext() const {
528-
return ContextAndBits.getPointer();
529-
}
587+
DeclContext *getDeclContext() const { return Context; }
530588

531589
/// Get any additional requirements that are required for this conformance to
532590
/// be satisfied, e.g. for Array<T>: Equatable, T: Equatable also needs
@@ -538,59 +596,59 @@ class NormalProtocolConformance : public RootProtocolConformance,
538596

539597
/// Retrieve the state of this conformance.
540598
ProtocolConformanceState getState() const {
541-
return ProtocolAndState.getInt();
599+
return static_cast<ProtocolConformanceState>(
600+
Bits.NormalProtocolConformance.State);
542601
}
543602

544603
/// Set the state of this conformance.
545604
void setState(ProtocolConformanceState state) {
546-
ProtocolAndState.setInt(state);
605+
Bits.NormalProtocolConformance.State = unsigned(state);
547606
}
548607

549608
/// Determine whether this conformance is invalid.
550-
bool isInvalid() const {
551-
return Invalid;
552-
}
609+
bool isInvalid() const { return Bits.NormalProtocolConformance.IsInvalid; }
553610

554611
/// Mark this conformance as invalid.
555-
void setInvalid() {
556-
Invalid = true;
557-
}
612+
void setInvalid() { Bits.NormalProtocolConformance.IsInvalid = true; }
558613

559614
/// Whether this is an "unchecked" conformance.
560615
bool isUnchecked() const {
561-
return ContextAndBits.getInt() & UncheckedFlag;
616+
return Bits.NormalProtocolConformance.IsUnchecked;
562617
}
563618

564619
/// Mark the conformance as unchecked (equivalent to the @unchecked
565620
/// conformance attribute).
566621
void setUnchecked() {
567622
// OK to mutate because the flags are not part of the folding set node ID.
568-
ContextAndBits.setInt(ContextAndBits.getInt() | UncheckedFlag);
623+
Bits.NormalProtocolConformance.IsUnchecked = true;
569624
}
570625

571626
/// Whether this is an preconcurrency conformance.
572-
bool isPreconcurrency() const;
627+
bool isPreconcurrency() const {
628+
return Bits.NormalProtocolConformance.IsPreconcurrency;
629+
}
573630

574631
/// Determine whether we've lazily computed the associated conformance array
575632
/// already.
576633
bool hasComputedAssociatedConformances() const {
577-
return ContextAndBits.getInt() & HasComputedAssociatedConformancesFlag;
634+
return Bits.NormalProtocolConformance.HasComputedAssociatedConformances;
578635
}
579636

580637
/// Mark this conformance as having computed the assocaited conformance array.
581638
void setHasComputedAssociatedConformances() {
582-
ContextAndBits.setInt(ContextAndBits.getInt() | HasComputedAssociatedConformancesFlag);
639+
Bits.NormalProtocolConformance.HasComputedAssociatedConformances = true;
583640
}
584641

585642
/// Get the kind of source from which this conformance comes.
586643
ConformanceEntryKind getSourceKind() const {
587-
return SourceKindAndImplyingConformance.getInt();
644+
return static_cast<ConformanceEntryKind>(
645+
Bits.NormalProtocolConformance.SourceKind);
588646
}
589647

590648
/// Get the protocol conformance which implied this implied conformance.
591649
NormalProtocolConformance *getImplyingConformance() const {
592650
assert(getSourceKind() == ConformanceEntryKind::Implied);
593-
return SourceKindAndImplyingConformance.getPointer();
651+
return ImplyingConformance;
594652
}
595653

596654
void setSourceKindAndImplyingConformance(
@@ -603,7 +661,8 @@ class NormalProtocolConformance : public RootProtocolConformance,
603661
"an implied conformance needs something that implies it");
604662
assert(sourceKind != ConformanceEntryKind::PreMacroExpansion &&
605663
"cannot create conformance pre-macro-expansion");
606-
SourceKindAndImplyingConformance = {implyingConformance, sourceKind};
664+
Bits.NormalProtocolConformance.SourceKind = unsigned(sourceKind);
665+
ImplyingConformance = implyingConformance;
607666
}
608667

609668
/// Determine whether this conformance is lazily loaded.
@@ -1056,22 +1115,12 @@ class InheritedProtocolConformance : public ProtocolConformance,
10561115
}
10571116
};
10581117

1059-
/// Describes the kind of a builtin conformance.
1060-
enum class BuiltinConformanceKind {
1061-
// A builtin conformance that has been synthesized by the implementation.
1062-
Synthesized = 0,
1063-
// A missing conformance that we have nonetheless synthesized so that
1064-
// we can diagnose it later.
1065-
Missing,
1066-
};
1067-
10681118
/// A builtin conformance appears when a non-nominal type has a
10691119
/// conformance that is synthesized by the implementation.
10701120
class BuiltinProtocolConformance final : public RootProtocolConformance {
10711121
friend ASTContext;
10721122

10731123
ProtocolDecl *protocol;
1074-
unsigned builtinConformanceKind;
10751124

10761125
BuiltinProtocolConformance(Type conformingType, ProtocolDecl *protocol,
10771126
BuiltinConformanceKind kind);
@@ -1083,7 +1132,8 @@ class BuiltinProtocolConformance final : public RootProtocolConformance {
10831132
}
10841133

10851134
BuiltinConformanceKind getBuiltinConformanceKind() const {
1086-
return static_cast<BuiltinConformanceKind>(builtinConformanceKind);
1135+
return static_cast<BuiltinConformanceKind>(
1136+
Bits.BuiltinProtocolConformance.Kind);
10871137
}
10881138

10891139
GenericSignature getGenericSignature() const {

lib/AST/ProtocolConformance.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,6 @@ bool NormalProtocolConformance::isResilient() const {
338338
return getDeclContext()->getParentModule()->isResilient();
339339
}
340340

341-
bool NormalProtocolConformance::isPreconcurrency() const {
342-
// The conformance is explicitly marked as `@preconcurrency`.
343-
return ContextAndBits.getInt() & PreconcurrencyFlag;
344-
}
345-
346341
llvm::Optional<ArrayRef<Requirement>>
347342
ProtocolConformance::getConditionalRequirementsIfAvailable() const {
348343
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirementsIfAvailable, ());
@@ -1494,11 +1489,11 @@ ProtocolConformance *ProtocolConformance::getCanonicalConformance() {
14941489
}
14951490

14961491
BuiltinProtocolConformance::BuiltinProtocolConformance(
1497-
Type conformingType, ProtocolDecl *protocol,
1498-
BuiltinConformanceKind kind
1499-
) : RootProtocolConformance(ProtocolConformanceKind::Builtin, conformingType),
1500-
protocol(protocol), builtinConformanceKind(static_cast<unsigned>(kind))
1501-
{}
1492+
Type conformingType, ProtocolDecl *protocol, BuiltinConformanceKind kind)
1493+
: RootProtocolConformance(ProtocolConformanceKind::Builtin, conformingType),
1494+
protocol(protocol) {
1495+
Bits.BuiltinProtocolConformance.Kind = unsigned(kind);
1496+
}
15021497

15031498
// See swift/Basic/Statistic.h for declaration: this enables tracing
15041499
// ProtocolConformances, is defined here to avoid too much layering violation /

0 commit comments

Comments
 (0)