| //===------------- TypeLayout.h --------------- Type layouts ---*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_IRGEN_TYPE_LAYOUT_H |
| #define SWIFT_IRGEN_TYPE_LAYOUT_H |
| |
| #include "TypeInfo.h" |
| #include "swift/SIL/SILType.h" |
| #include "llvm/ADT/FoldingSet.h" |
| #include "llvm/Support/Debug.h" |
| |
| namespace swift { |
| namespace irgen { |
| |
| class EnumTypeLayoutEntry; |
| |
| enum class TypeLayoutEntryKind : uint8_t { |
| Empty, |
| Scalar, |
| Archetype, |
| AlignedGroup, |
| Resilient, |
| Enum, |
| }; |
| |
| class TypeLayoutEntry { |
| public: |
| TypeLayoutEntryKind kind; |
| uint8_t hasArchetypeField : 1; |
| uint8_t hasResilientField : 1; |
| uint8_t hasDependentResilientField : 1; |
| |
| TypeLayoutEntry() |
| : kind(TypeLayoutEntryKind::Empty), hasArchetypeField(false), |
| hasResilientField(false), hasDependentResilientField(false) {} |
| |
| TypeLayoutEntry(TypeLayoutEntryKind kind) |
| : kind(kind), hasArchetypeField(false), hasResilientField(false), |
| hasDependentResilientField(false) {} |
| |
| virtual ~TypeLayoutEntry(); |
| |
| virtual void computeProperties(); |
| |
| bool containsResilientField() const; |
| bool containsArchetypeField() const; |
| bool containsDependentResilientField() const; |
| |
| |
| bool isEmpty() const { return kind == TypeLayoutEntryKind::Empty; } |
| |
| TypeLayoutEntryKind getKind() const { return kind; } |
| |
| virtual llvm::Value *alignmentMask(IRGenFunction &IGF) const; |
| virtual llvm::Value *size(IRGenFunction &IGF) const; |
| virtual llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const; |
| virtual llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const; |
| |
| virtual void destroy(IRGenFunction &IGF, Address addr) const; |
| |
| void assign(IRGenFunction &IGF, Address dest, Address src, |
| IsTake_t isTake) const; |
| void initialize(IRGenFunction &IGF, Address dest, Address src, |
| IsTake_t isTake) const; |
| |
| virtual void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const; |
| virtual void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const; |
| |
| virtual void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const; |
| virtual void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const; |
| |
| /// Returns a pointer to the object (T*) inside of the buffer. |
| virtual llvm::Value *initBufferWithCopyOfBuffer(IRGenFunction &IGF, |
| Address dest, |
| Address src) const; |
| |
| virtual llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const; |
| |
| virtual void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const; |
| |
| const EnumTypeLayoutEntry *getAsEnum() const; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| LLVM_DUMP_METHOD virtual void dump() const { |
| assert(isEmpty() && "Missing subclass implementation?"); |
| llvm::dbgs() << "{empty}"; |
| } |
| #endif |
| protected: |
| llvm::Value * |
| getEnumTagSinglePayloadGeneric(IRGenFunction &IGF, Address addr, |
| llvm::Value *numEmptyCases, |
| llvm::function_ref<llvm::Value *(Address addr)> |
| getExtraInhabitantIndexFun) const; |
| |
| void storeEnumTagSinglePayloadGeneric( |
| IRGenFunction &IGF, llvm::Value *tag, llvm::Value *numEmptyCases, |
| Address addr, |
| llvm::function_ref<void(Address addr, llvm::Value *tag)> |
| storeExtraInhabitantIndexFun) const; |
| |
| void gatherProperties(TypeLayoutEntry *fromEntry); |
| }; |
| |
| class ScalarTypeLayoutEntry : public TypeLayoutEntry, |
| public llvm::FoldingSetNode { |
| public: |
| const TypeInfo &typeInfo; |
| SILType representative; |
| |
| ScalarTypeLayoutEntry(const TypeInfo &ti, SILType representative) |
| : TypeLayoutEntry(TypeLayoutEntryKind::Scalar), typeInfo(ti), |
| representative(representative) {} |
| |
| ~ScalarTypeLayoutEntry(); |
| |
| void computeProperties() override; |
| |
| // Support for FoldingSet. |
| void Profile(llvm::FoldingSetNodeID &id) const; |
| static void Profile(llvm::FoldingSetNodeID &ID, const TypeInfo &ti, |
| SILType ty); |
| |
| llvm::Value *alignmentMask(IRGenFunction &IGF) const override; |
| llvm::Value *size(IRGenFunction &IGF) const override; |
| llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const override; |
| llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const override; |
| |
| void destroy(IRGenFunction &IGF, Address addr) const override; |
| |
| void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const override; |
| |
| void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const override; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| void dump() const override; |
| #endif |
| |
| }; |
| |
| class ArchetypeLayoutEntry : public TypeLayoutEntry, |
| public llvm::FoldingSetNode { |
| SILType archetype; |
| |
| public: |
| ArchetypeLayoutEntry(SILType archetype) |
| : TypeLayoutEntry(TypeLayoutEntryKind::Archetype), archetype(archetype) {} |
| |
| ~ArchetypeLayoutEntry(); |
| |
| void computeProperties() override; |
| |
| // Support for FoldingSet. |
| void Profile(llvm::FoldingSetNodeID &id) const; |
| static void Profile(llvm::FoldingSetNodeID &ID, SILType archetype); |
| |
| llvm::Value *alignmentMask(IRGenFunction &IGF) const override; |
| llvm::Value *size(IRGenFunction &IGF) const override; |
| llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const override; |
| llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const override; |
| |
| void destroy(IRGenFunction &IGF, Address addr) const override; |
| |
| void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const override; |
| |
| void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const override; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| void dump() const override; |
| #endif |
| }; |
| |
| class ResilientTypeLayoutEntry : public TypeLayoutEntry, |
| public llvm::FoldingSetNode { |
| SILType ty; |
| |
| public: |
| ResilientTypeLayoutEntry(SILType ty) |
| : TypeLayoutEntry(TypeLayoutEntryKind::Resilient), ty(ty) {} |
| |
| ~ResilientTypeLayoutEntry(); |
| |
| void computeProperties() override; |
| |
| // Support for FoldingSet. |
| void Profile(llvm::FoldingSetNodeID &id) const; |
| static void Profile(llvm::FoldingSetNodeID &ID, SILType ty); |
| |
| llvm::Value *alignmentMask(IRGenFunction &IGF) const override; |
| llvm::Value *size(IRGenFunction &IGF) const override; |
| llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const override; |
| llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const override; |
| |
| void destroy(IRGenFunction &IGF, Address addr) const override; |
| |
| void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const override; |
| |
| void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const override; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| void dump() const override; |
| #endif |
| }; |
| |
| class AlignedGroupEntry : public TypeLayoutEntry, public llvm::FoldingSetNode { |
| std::vector<TypeLayoutEntry *> entries; |
| Alignment::int_type minimumAlignment; |
| bool isFixedSize; |
| |
| public: |
| AlignedGroupEntry(std::vector<TypeLayoutEntry *> &entries, |
| Alignment::int_type minimumAlignment, bool isFixedSize) |
| : TypeLayoutEntry(TypeLayoutEntryKind::AlignedGroup), entries(entries), |
| minimumAlignment(minimumAlignment), isFixedSize(isFixedSize) {} |
| |
| ~AlignedGroupEntry(); |
| |
| void computeProperties() override; |
| |
| // Support for FoldingSet. |
| void Profile(llvm::FoldingSetNodeID &id) const; |
| static void Profile(llvm::FoldingSetNodeID &ID, |
| const std::vector<TypeLayoutEntry *> &entries, |
| Alignment::int_type minimumAlignment, bool isFixedSize); |
| |
| llvm::Value *alignmentMask(IRGenFunction &IGF) const override; |
| llvm::Value *size(IRGenFunction &IGF) const override; |
| llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const override; |
| llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const override; |
| |
| void destroy(IRGenFunction &IGF, Address addr) const override; |
| |
| void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const override; |
| |
| void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const override; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| void dump() const override; |
| #endif |
| |
| private: |
| llvm::Value *withExtraInhabitantProvidingEntry( |
| IRGenFunction &IGF, Address addr, llvm::Type *returnType, |
| llvm::function_ref<llvm::Value *(TypeLayoutEntry *, |
| Address /*entry addr*/, |
| llvm::Value * /*entry xi count*/)> |
| entryFun) const; |
| void |
| withEachEntry(IRGenFunction &IGF, Address dest, Address src, |
| llvm::function_ref<void(TypeLayoutEntry *entry, |
| Address entryDest, Address entrySrc)> |
| entryFun) const; |
| }; |
| |
| class EnumTypeLayoutEntry : public TypeLayoutEntry, |
| public llvm::FoldingSetNode { |
| public: |
| unsigned numEmptyCases; |
| unsigned minimumAlignment; |
| std::vector<TypeLayoutEntry *> cases; |
| |
| EnumTypeLayoutEntry(unsigned numEmptyCases, |
| const std::vector<TypeLayoutEntry *> &cases) |
| : TypeLayoutEntry(TypeLayoutEntryKind::Enum), |
| numEmptyCases(numEmptyCases), minimumAlignment(1), cases(cases) {} |
| |
| ~EnumTypeLayoutEntry(); |
| |
| void computeProperties() override; |
| |
| // Support for FoldingSet. |
| void Profile(llvm::FoldingSetNodeID &id) const; |
| static void Profile(llvm::FoldingSetNodeID &ID, unsigned numEmptyCases, |
| const std::vector<TypeLayoutEntry *> &cases); |
| |
| llvm::Value *alignmentMask(IRGenFunction &IGF) const override; |
| llvm::Value *size(IRGenFunction &IGF) const override; |
| llvm::Value *extraInhabitantCount(IRGenFunction &IGF) const override; |
| llvm::Value *isBitwiseTakable(IRGenFunction &IGF) const override; |
| |
| void destroy(IRGenFunction &IGF, Address addr) const override; |
| |
| void assignWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void assignWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| void initWithCopy(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| void initWithTake(IRGenFunction &IGF, Address dest, |
| Address src) const override; |
| |
| llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF, |
| llvm::Value *numEmptyCases, |
| Address addr) const override; |
| |
| void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const override; |
| |
| llvm::Value *getEnumTag(IRGenFunction &IGF, Address enumAddr) const; |
| |
| void destructiveProjectEnumData(IRGenFunction &IGF, Address enumAddr) const; |
| |
| void destructiveInjectEnumTag(IRGenFunction &IGF, llvm::Value *tag, |
| Address enumAddr) const; |
| |
| bool isMultiPayloadEnum() const; |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| void dump() const override; |
| #endif |
| |
| private: |
| llvm::Value *maxPayloadSize(IRGenFunction &IGF) const; |
| llvm::BasicBlock *testSinglePayloadEnumContainsPayload(IRGenFunction &IGF, |
| Address addr) const; |
| |
| void initializeSinglePayloadEnum(IRGenFunction &IGF, Address dest, |
| Address src, IsTake_t isTake) const; |
| void assignSinglePayloadEnum(IRGenFunction &IGF, Address dest, Address src, |
| IsTake_t isTake) const; |
| |
| void initializeMultiPayloadEnum(IRGenFunction &IGF, Address dest, |
| Address src, IsTake_t isTake) const; |
| void assignMultiPayloadEnum(IRGenFunction &IGF, Address dest, Address src, |
| IsTake_t isTake) const; |
| |
| std::pair<Address, llvm::Value *> |
| getMultiPalyloadEnumTagByteAddrAndNumBytes(IRGenFunction &IGF, |
| Address addr) const; |
| |
| llvm::Value * |
| getEnumTagSinglePayloadForSinglePayloadEnum(IRGenFunction &IGF, Address addr, |
| llvm::Value *numEmptyCases) const; |
| void storeEnumTagSinglePayloadForSinglePayloadEnum(IRGenFunction &IGF, |
| llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const; |
| llvm::Value * |
| getEnumTagSinglePayloadForMultiPayloadEnum(IRGenFunction &IGF, Address addr, |
| llvm::Value *numEmptyCases) const; |
| void storeEnumTagSinglePayloadForMultiPayloadEnum(IRGenFunction &IGF, |
| llvm::Value *tag, |
| llvm::Value *numEmptyCases, |
| Address enumAddr) const; |
| llvm::Value *getEnumTagMultipayload(IRGenFunction &IGF, |
| Address enumAddr) const; |
| |
| void storeEnumTagMultipayload(IRGenFunction &IGF, llvm::Value *tag, |
| Address enumAddr) const; |
| |
| /// Store a value to the enum's tag bytes. |
| void storeMultiPayloadTag(IRGenFunction &IGF, llvm::Value *value, |
| Address enumAddr) const; |
| /// Store a value to the enum's payload bytes. |
| void storeMultiPayloadValue(IRGenFunction &IGF, llvm::Value *value, |
| Address enumAddr) const; |
| |
| void destroyMultiPayloadEnum(IRGenFunction &IGF, Address enumAddr) const; |
| void destroySinglePayloadEnum(IRGenFunction &IGF, Address enumAddr) const; |
| |
| void multiPayloadEnumForPayloadAndEmptyCases( |
| IRGenFunction &IGF, Address addr, |
| llvm::function_ref<void(TypeLayoutEntry *payload, llvm::Value *tagIndex)> |
| payloadFunction, |
| llvm::function_ref<void()> noPayloadFunction) const; |
| }; |
| |
| class TypeLayoutCache { |
| llvm::BumpPtrAllocator bumpAllocator; |
| |
| llvm::FoldingSet<ScalarTypeLayoutEntry> scalarEntries; |
| llvm::FoldingSet<ArchetypeLayoutEntry> archetypeEntries; |
| llvm::FoldingSet<AlignedGroupEntry> alignedGroupEntries; |
| llvm::FoldingSet<EnumTypeLayoutEntry> enumEntries; |
| llvm::FoldingSet<ResilientTypeLayoutEntry> resilientEntries; |
| |
| TypeLayoutEntry emptyEntry; |
| public: |
| ~TypeLayoutCache(); |
| ScalarTypeLayoutEntry *getOrCreateScalarEntry(const TypeInfo &ti, |
| SILType representative); |
| |
| ArchetypeLayoutEntry *getOrCreateArchetypeEntry(SILType archetype); |
| |
| AlignedGroupEntry * |
| getOrCreateAlignedGroupEntry(std::vector<TypeLayoutEntry *> &entries, |
| Alignment::int_type minimumAlignment, |
| bool isFixedSize); |
| |
| EnumTypeLayoutEntry * |
| getOrCreateEnumEntry(unsigned numEmptyCase, |
| const std::vector<TypeLayoutEntry *> &nonEmptyCases); |
| |
| ResilientTypeLayoutEntry *getOrCreateResilientEntry(SILType ty); |
| |
| TypeLayoutEntry *getEmptyEntry(); |
| }; |
| |
| } // namespace irgen |
| } // namespace swift |
| #endif |