Skip to content

NFC: Save memory by repacking bits into bitfields #13363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 106 additions & 56 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,12 @@ bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2);
#define BITFIELD_START(D, PD, C) \
enum { Num##D##Bits = Num##PD##Bits + C }; \
static_assert(Num##D##Bits <= 64, "fits in a uint64_t"); \
LLVM_PACKED_START; \
class D##Bitfields { \
friend class D; \
uint64_t : Num##PD##Bits

#define BITFIELD_END }
#define BITFIELD_END }; LLVM_PACKED_END

/// Decl - Base class for all declarations in Swift.
class alignas(1 << DeclAlignInBits) Decl {
Expand Down Expand Up @@ -282,6 +283,13 @@ class alignas(1 << DeclAlignInBits) Decl {
unsigned NumPatternEntries : 16;
BITFIELD_END;

BITFIELD_START(EnumCaseDecl, Decl, 51);
unsigned : 19; // unused / padding

/// The number of tail-allocated element pointers.
unsigned NumElements : 32;
BITFIELD_END;

BITFIELD_START(ValueDecl, Decl, 3);
friend class MemberLookupTable;

Expand Down Expand Up @@ -353,13 +361,16 @@ class alignas(1 << DeclAlignInBits) Decl {
unsigned HasArgumentType : 1;
BITFIELD_END;

BITFIELD_START(AbstractFunctionDecl, ValueDecl, 13);
BITFIELD_START(AbstractFunctionDecl, ValueDecl, 21);
/// \see AbstractFunctionDecl::BodyKind
unsigned BodyKind : 3;

/// Number of curried parameter lists.
unsigned NumParameterLists : 5;

/// Import as member status.
unsigned IAMStatus : 8;

/// Whether we are overridden later.
unsigned Overridden : 1;

Expand Down Expand Up @@ -424,6 +435,16 @@ class alignas(1 << DeclAlignInBits) Decl {
unsigned CheckedInheritanceClause : 1;
BITFIELD_END;

BITFIELD_START(AbstractTypeParamDecl, TypeDecl, 0);
BITFIELD_END;

BITFIELD_START(GenericTypeParamDecl, AbstractTypeParamDecl, 47);
unsigned : 15; // unused padding

unsigned Depth : 16;
unsigned Index : 16;
BITFIELD_END;

BITFIELD_START(GenericTypeDecl, TypeDecl, 0);
BITFIELD_END;

Expand All @@ -449,7 +470,7 @@ class alignas(1 << DeclAlignInBits) Decl {
unsigned HasValidatedLayout : 1;
BITFIELD_END;

BITFIELD_START(ProtocolDecl, NominalTypeDecl, 8);
BITFIELD_START(ProtocolDecl, NominalTypeDecl, 43);
/// Whether the \c RequiresClass bit is valid.
unsigned RequiresClassValid : 1;

Expand All @@ -468,11 +489,24 @@ class alignas(1 << DeclAlignInBits) Decl {
/// Whether the existential of this protocol can be represented.
unsigned ExistentialTypeSupported : 1;

/// True if the protocol has requirements that cannot be satisfied (e.g.
/// because they could not be imported from Objective-C).
unsigned HasMissingRequirements : 1;

unsigned : 12; // unused flags

/// If this is a compiler-known protocol, this will be a KnownProtocolKind
/// value, plus one. Otherwise, it will be 0.
unsigned KnownProtocol : 6;

/// The stage of the circularity check for this protocol.
unsigned Circularity : 2;

/// The number of requirements in the requirement signature.
unsigned NumRequirementsInSignature : 16;
BITFIELD_END;

BITFIELD_START(ClassDecl, NominalTypeDecl, 8);
BITFIELD_START(ClassDecl, NominalTypeDecl, 13);
/// The stage of the inheritance circularity check for this class.
unsigned Circularity : 2;

Expand All @@ -495,6 +529,12 @@ class alignas(1 << DeclAlignInBits) Decl {
/// it is implicit. This bit is used during parsing and type-checking to
/// control inserting the implicit destructor.
unsigned HasDestructorDecl : 1;

/// Whether the class has @objc ancestry.
unsigned ObjCKind : 3;

unsigned HasMissingDesignatedInitializers : 1;
unsigned HasMissingVTableEntries : 1;
BITFIELD_END;

BITFIELD_START(StructDecl, NominalTypeDecl, 1);
Expand Down Expand Up @@ -524,8 +564,11 @@ class alignas(1 << DeclAlignInBits) Decl {
unsigned HasOverridden : 1;
BITFIELD_END;

BITFIELD_START(ImportDecl, Decl, 3);
BITFIELD_START(ImportDecl, Decl, 11);
unsigned ImportKind : 3;

/// The number of elements in this path.
unsigned NumPathElements : 8;
BITFIELD_END;

BITFIELD_START(ExtensionDecl, Decl, 5);
Expand Down Expand Up @@ -561,6 +604,7 @@ class alignas(1 << DeclAlignInBits) Decl {
union {
DeclBitfields DeclBits;
PatternBindingDeclBitfields PatternBindingDeclBits;
EnumCaseDeclBitfields EnumCaseDeclBits;
ValueDeclBitfields ValueDeclBits;
AbstractStorageDeclBitfields AbstractStorageDeclBits;
AbstractFunctionDeclBitfields AbstractFunctionDeclBits;
Expand All @@ -570,6 +614,8 @@ class alignas(1 << DeclAlignInBits) Decl {
FuncDeclBitfields FuncDeclBits;
ConstructorDeclBitfields ConstructorDeclBits;
TypeDeclBitfields TypeDeclBits;
AbstractTypeParamDeclBitfields AbstractTypeParamDeclBit;
GenericTypeParamDeclBitfields GenericTypeParamDeclBits;
GenericTypeDeclBitfields GenericTypeDeclBits;
TypeAliasDeclBitfields TypeAliasDeclBits;
NominalTypeDeclBitfields NominalTypeDeclBits;
Expand Down Expand Up @@ -1450,9 +1496,6 @@ class ImportDecl final : public Decl,
SourceLoc ImportLoc;
SourceLoc KindLoc;

/// The number of elements in this path.
unsigned NumPathElements;

/// The resolved module.
ModuleDecl *Mod = nullptr;
/// The resolved decls if this is a decl import.
Expand Down Expand Up @@ -1481,7 +1524,8 @@ class ImportDecl final : public Decl,
static Optional<ImportKind> findBestImportKind(ArrayRef<ValueDecl *> Decls);

ArrayRef<AccessPathElement> getFullAccessPath() const {
return {getTrailingObjects<AccessPathElement>(), NumPathElements};
return {getTrailingObjects<AccessPathElement>(),
ImportDeclBits.NumPathElements};
}

ArrayRef<AccessPathElement> getModulePath() const {
Expand Down Expand Up @@ -2481,9 +2525,6 @@ class AbstractTypeParamDecl : public TypeDecl {
/// func min<T : Comparable>(x : T, y : T) -> T { ... }
/// \endcode
class GenericTypeParamDecl : public AbstractTypeParamDecl {
unsigned Depth : 16;
unsigned Index : 16;

public:
static const unsigned InvalidDepth = 0xFFFF;

Expand All @@ -2508,12 +2549,15 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
/// \endcode
///
/// Here 'T' has depth 0 and 'U' has depth 1. Both have index 0.
unsigned getDepth() const { return Depth; }
unsigned getDepth() const { return GenericTypeParamDeclBits.Depth; }

/// Set the depth of this generic type parameter.
///
/// \sa getDepth
void setDepth(unsigned depth) { Depth = depth; }
void setDepth(unsigned depth) {
GenericTypeParamDeclBits.Depth = depth;
assert(GenericTypeParamDeclBits.Depth == depth && "Truncation");
}

/// The index of this generic type parameter within its generic parameter
/// list.
Expand All @@ -2525,7 +2569,7 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
/// \endcode
///
/// Here 'T' and 'U' have indexes 0 and 1, respectively. 'V' has index 0.
unsigned getIndex() const { return Index; }
unsigned getIndex() const { return GenericTypeParamDeclBits.Index; }

SourceLoc getStartLoc() const { return getNameLoc(); }
SourceRange getSourceRange() const;
Expand Down Expand Up @@ -3226,12 +3270,6 @@ class ClassDecl final : public NominalTypeDecl {
llvm::PointerIntPair<Type, 1, bool> Superclass;
} LazySemanticInfo;

/// Whether the class has @objc ancestry.
unsigned ObjCKind : 3;

unsigned HasMissingDesignatedInitializers : 1;
unsigned HasMissingVTableEntries : 1;

friend class IterativeTypeChecker;

public:
Expand Down Expand Up @@ -3324,7 +3362,7 @@ class ClassDecl final : public NominalTypeDecl {
bool hasMissingDesignatedInitializers() const;

void setHasMissingDesignatedInitializers(bool newValue = true) {
HasMissingDesignatedInitializers = newValue;
ClassDeclBits.HasMissingDesignatedInitializers = newValue;
}

/// Returns true if the class has missing members that require vtable entries.
Expand All @@ -3334,7 +3372,7 @@ class ClassDecl final : public NominalTypeDecl {
bool hasMissingVTableEntries() const;

void setHasMissingVTableEntries(bool newValue = true) {
HasMissingVTableEntries = newValue;
ClassDeclBits.HasMissingVTableEntries = newValue;
}

/// Find a method of a class that overrides a given method.
Expand Down Expand Up @@ -3523,17 +3561,6 @@ class ProtocolDecl final : public NominalTypeDecl {
/// by this protocol.
const Requirement *RequirementSignature = nullptr;

/// True if the protocol has requirements that cannot be satisfied (e.g.
/// because they could not be imported from Objective-C).
unsigned HasMissingRequirements : 1;

/// If this is a compiler-known protocol, this will be a KnownProtocolKind
/// value, plus one. Otherwise, it will be 0.
unsigned KnownProtocol : 6;

/// The number of requirements in the requirement signature.
unsigned NumRequirementsInSignature : 16;

bool requiresClassSlow();

bool existentialConformsToSelfSlow();
Expand Down Expand Up @@ -3653,9 +3680,9 @@ class ProtocolDecl final : public NominalTypeDecl {
///
/// Note that this is only valid after type-checking.
Optional<KnownProtocolKind> getKnownProtocolKind() const {
if (KnownProtocol == 0)
if (ProtocolDeclBits.KnownProtocol == 0)
return None;
return static_cast<KnownProtocolKind>(KnownProtocol - 1);
return static_cast<KnownProtocolKind>(ProtocolDeclBits.KnownProtocol - 1);
}

/// Check whether this protocol is of a specific, known protocol kind.
Expand All @@ -3670,7 +3697,7 @@ class ProtocolDecl final : public NominalTypeDecl {
void setKnownProtocolKind(KnownProtocolKind kind) {
assert((!getKnownProtocolKind() || *getKnownProtocolKind() == kind) &&
"can't reset known protocol kind");
KnownProtocol = static_cast<unsigned>(kind) + 1;
ProtocolDeclBits.KnownProtocol = static_cast<unsigned>(kind) + 1;
assert(getKnownProtocolKind() && *getKnownProtocolKind() == kind &&
"not enough bits");
}
Expand All @@ -3692,11 +3719,11 @@ class ProtocolDecl final : public NominalTypeDecl {
/// with requirements that cannot be represented in Swift.
bool hasMissingRequirements() const {
(void)getMembers();
return HasMissingRequirements;
return ProtocolDeclBits.HasMissingRequirements;
}

void setHasMissingRequirements(bool newValue) {
HasMissingRequirements = newValue;
ProtocolDeclBits.HasMissingRequirements = newValue;
}

/// Returns the default witness for a requirement, or nullptr if there is
Expand Down Expand Up @@ -3733,7 +3760,8 @@ class ProtocolDecl final : public NominalTypeDecl {
ArrayRef<Requirement> getRequirementSignature() const {
assert(isRequirementSignatureComputed() &&
"getting requirement signature before computing it");
return llvm::makeArrayRef(RequirementSignature, NumRequirementsInSignature);
return llvm::makeArrayRef(RequirementSignature,
ProtocolDeclBits.NumRequirementsInSignature);
}

/// Has the requirement signature been computed yet?
Expand Down Expand Up @@ -4784,10 +4812,17 @@ class SubscriptDecl : public AbstractStorageDecl, public GenericContext {

/// Encodes imported-as-member status for C functions that get imported
/// as methods.
struct ImportAsMemberStatus {
class ImportAsMemberStatus {
friend class AbstractFunctionDecl;

// non-0 denotes import-as-member. 1 denotes no self index. n+2 denotes self
// index of n
uint8_t rawValue = 0;
uint8_t rawValue;

public:
ImportAsMemberStatus(uint8_t rawValue = 0) : rawValue(rawValue) {}

uint8_t getRawValue() const { return rawValue; }

bool isImportAsMember() const { return rawValue != 0; }
bool isInstance() const { return rawValue >= 2; }
Expand Down Expand Up @@ -4864,8 +4899,6 @@ class AbstractFunctionDecl : public ValueDecl, public GenericContext {
/// Location of the 'throws' token.
SourceLoc ThrowsLoc;

ImportAsMemberStatus IAMStatus;

AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
unsigned NumParameterLists,
Expand Down Expand Up @@ -4903,14 +4936,32 @@ class AbstractFunctionDecl : public ValueDecl, public GenericContext {
bool isTransparent() const;

// Expose our import as member status
bool isImportAsMember() const { return IAMStatus.isImportAsMember(); }
bool isImportAsInstanceMember() const { return IAMStatus.isInstance(); }
bool isImportAsStaticMember() const { return IAMStatus.isStatic(); }
uint8_t getSelfIndex() const { return IAMStatus.getSelfIndex(); }
ImportAsMemberStatus getImportAsMemberStatus() const { return IAMStatus; }
ImportAsMemberStatus getImportAsMemberStatus() const {
return ImportAsMemberStatus(AbstractFunctionDeclBits.IAMStatus);
}
bool isImportAsMember() const {
return getImportAsMemberStatus().isImportAsMember();
}
bool isImportAsInstanceMember() const {
return getImportAsMemberStatus().isInstance();
}
bool isImportAsStaticMember() const {
return getImportAsMemberStatus().isStatic();
}
uint8_t getSelfIndex() const {
return getImportAsMemberStatus().getSelfIndex();
}

void setImportAsStaticMember() { IAMStatus.setStatic(); }
void setSelfIndex(uint8_t idx) { return IAMStatus.setSelfIndex(idx); }
void setImportAsStaticMember() {
auto newValue = getImportAsMemberStatus();
newValue.setStatic();
AbstractFunctionDeclBits.IAMStatus = newValue.getRawValue();
}
void setSelfIndex(uint8_t idx) {
auto newValue = getImportAsMemberStatus();
newValue.setSelfIndex(idx);
AbstractFunctionDeclBits.IAMStatus = newValue.getRawValue();
}

public:
/// Retrieve the location of the 'throws' keyword, if present.
Expand Down Expand Up @@ -5461,15 +5512,13 @@ class EnumCaseDecl final : public Decl,
friend TrailingObjects;
SourceLoc CaseLoc;

/// The number of tail-allocated element pointers.
unsigned NumElements;

EnumCaseDecl(SourceLoc CaseLoc,
ArrayRef<EnumElementDecl *> Elements,
DeclContext *DC)
: Decl(DeclKind::EnumCase, DC),
CaseLoc(CaseLoc), NumElements(Elements.size())
CaseLoc(CaseLoc)
{
EnumCaseDeclBits.NumElements = Elements.size();
std::uninitialized_copy(Elements.begin(), Elements.end(),
getTrailingObjects<EnumElementDecl *>());
}
Expand All @@ -5481,7 +5530,8 @@ class EnumCaseDecl final : public Decl,

/// Get the list of elements declared in this case.
ArrayRef<EnumElementDecl *> getElements() const {
return {getTrailingObjects<EnumElementDecl *>(), NumElements};
return {getTrailingObjects<EnumElementDecl *>(),
EnumCaseDeclBits.NumElements};
}

SourceLoc getLoc() const {
Expand Down
Loading