|
| 1 | +//===--- SILTypeProperties.h - Properties of SIL types ----------*- C++ -*-===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#ifndef SWIFT_SIL_SILTYPEPROPERTIES_H |
| 14 | +#define SWIFT_SIL_SILTYPEPROPERTIES_H |
| 15 | + |
| 16 | +namespace swift { |
| 17 | + |
| 18 | +/// Is a lowered SIL type trivial? That is, are copies ultimately just |
| 19 | +/// bit-copies, and it takes no work to destroy a value? |
| 20 | +enum IsTrivial_t : bool { |
| 21 | + IsNotTrivial = false, |
| 22 | + IsTrivial = true |
| 23 | +}; |
| 24 | + |
| 25 | +/// Is a lowered SIL type the Builtin.RawPointer or a struct/tuple/enum which |
| 26 | +/// contains a Builtin.RawPointer? |
| 27 | +/// HasRawPointer is true only for types that are known to contain |
| 28 | +/// Builtin.RawPointer. It is not assumed true for generic or resilient types. |
| 29 | +enum HasRawPointer_t : bool { |
| 30 | + DoesNotHaveRawPointer = false, |
| 31 | + HasRawPointer = true |
| 32 | +}; |
| 33 | + |
| 34 | +/// Is a lowered SIL type fixed-ABI? That is, can the current context |
| 35 | +/// assign it a fixed size and alignment and perform value operations on it |
| 36 | +/// (such as copies, destroys, constructions, and projections) without |
| 37 | +/// metadata? |
| 38 | +/// |
| 39 | +/// Note that a fully concrete type can be non-fixed-ABI without being |
| 40 | +/// itself resilient if it contains a subobject which is not fixed-ABI. |
| 41 | +/// |
| 42 | +/// Also note that we're only concerned with the external value ABI here: |
| 43 | +/// resilient class types are still fixed-ABI, indirect enum cases do not |
| 44 | +/// affect the fixed-ABI-ness of the enum, and so on. |
| 45 | +enum IsFixedABI_t : bool { |
| 46 | + IsNotFixedABI = false, |
| 47 | + IsFixedABI = true |
| 48 | +}; |
| 49 | + |
| 50 | +/// Is a lowered SIL type address-only? That is, is the current context |
| 51 | +/// required to keep the value in memory for some reason? |
| 52 | +/// |
| 53 | +/// A type might be address-only because: |
| 54 | +/// |
| 55 | +/// - it is not fixed-size (e.g. because it is a resilient type) and |
| 56 | +/// therefore cannot be loaded into a statically-boundable set of |
| 57 | +/// registers; or |
| 58 | +/// |
| 59 | +/// - it is semantically bound to memory, either because its storage |
| 60 | +/// address is used by the language runtime to implement its semantics |
| 61 | +/// (as with a weak reference) or because its representation is somehow |
| 62 | +/// address-dependent (as with something like a relative pointer). |
| 63 | +/// |
| 64 | +/// An address-only type can be fixed-layout and/or trivial. |
| 65 | +/// A non-fixed-layout type is always address-only. |
| 66 | +enum IsAddressOnly_t : bool { |
| 67 | + IsNotAddressOnly = false, |
| 68 | + IsAddressOnly = true |
| 69 | +}; |
| 70 | + |
| 71 | +/// Is this type somewhat like a reference-counted type? |
| 72 | +enum IsReferenceCounted_t : bool { |
| 73 | + IsNotReferenceCounted = false, |
| 74 | + IsReferenceCounted = true |
| 75 | +}; |
| 76 | + |
| 77 | +/// Is this type address only because it's resilient? |
| 78 | +enum IsResilient_t : bool { |
| 79 | + IsNotResilient = false, |
| 80 | + IsResilient = true |
| 81 | +}; |
| 82 | + |
| 83 | +/// Does this type contain an opaque result type that affects type lowering? |
| 84 | +enum IsTypeExpansionSensitive_t : bool { |
| 85 | + IsNotTypeExpansionSensitive = false, |
| 86 | + IsTypeExpansionSensitive = true |
| 87 | +}; |
| 88 | + |
| 89 | +/// Is the type infinitely defined in terms of itself? (Such types can never |
| 90 | +/// be concretely instantiated, but may still arise from generic specialization.) |
| 91 | +enum IsInfiniteType_t : bool { |
| 92 | + IsNotInfiniteType = false, |
| 93 | + IsInfiniteType = true, |
| 94 | +}; |
| 95 | + |
| 96 | +/// Does this type contain any pack-like thing. |
| 97 | +enum HasPack_t : bool { |
| 98 | + HasNoPack = false, |
| 99 | + HasPack = true, |
| 100 | +}; |
| 101 | + |
| 102 | +/// Is the type addressable-for-dependencies? |
| 103 | +/// |
| 104 | +/// Values of an addressable-for-dependency type are passed indirectly into |
| 105 | +/// functions that specify a return value lifetime dependency on the value. |
| 106 | +/// This allows the dependent value to safely contain pointers to the in-memory |
| 107 | +/// representation of the source of the dependency. |
| 108 | +enum IsAddressableForDependencies_t : bool { |
| 109 | + IsNotAddressableForDependencies = false, |
| 110 | + IsAddressableForDependencies = true, |
| 111 | +}; |
| 112 | + |
| 113 | +class SILTypeProperties { |
| 114 | + // These are chosen so that bitwise-or merges the flags properly. |
| 115 | + // |
| 116 | + // clang-format off |
| 117 | + enum : unsigned { |
| 118 | + NonTrivialFlag = 1 << 0, |
| 119 | + NonFixedABIFlag = 1 << 1, |
| 120 | + AddressOnlyFlag = 1 << 2, |
| 121 | + ResilientFlag = 1 << 3, |
| 122 | + TypeExpansionSensitiveFlag = 1 << 4, |
| 123 | + InfiniteFlag = 1 << 5, |
| 124 | + HasRawPointerFlag = 1 << 6, |
| 125 | + LexicalFlag = 1 << 7, |
| 126 | + HasPackFlag = 1 << 8, |
| 127 | + AddressableForDependenciesFlag = 1 << 9, |
| 128 | + }; |
| 129 | + // clang-format on |
| 130 | + |
| 131 | + uint16_t Flags; |
| 132 | + |
| 133 | +public: |
| 134 | + /// Construct a default SILTypeProperties, which corresponds to |
| 135 | + /// a trivial, loadable, fixed-layout type. |
| 136 | + constexpr SILTypeProperties() : Flags(0) {} |
| 137 | + |
| 138 | + constexpr SILTypeProperties( |
| 139 | + IsTrivial_t isTrivial, IsFixedABI_t isFixedABI, |
| 140 | + IsAddressOnly_t isAddressOnly, IsResilient_t isResilient, |
| 141 | + IsTypeExpansionSensitive_t isTypeExpansionSensitive = |
| 142 | + IsNotTypeExpansionSensitive, |
| 143 | + HasRawPointer_t hasRawPointer = DoesNotHaveRawPointer, |
| 144 | + IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack, |
| 145 | + IsAddressableForDependencies_t isAFD = IsNotAddressableForDependencies) |
| 146 | + : Flags((isTrivial ? 0U : NonTrivialFlag) | |
| 147 | + (isFixedABI ? 0U : NonFixedABIFlag) | |
| 148 | + (isAddressOnly ? AddressOnlyFlag : 0U) | |
| 149 | + (isResilient ? ResilientFlag : 0U) | |
| 150 | + (isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0U) | |
| 151 | + (hasRawPointer ? HasRawPointerFlag : 0U) | |
| 152 | + (isLexical ? LexicalFlag : 0U) | |
| 153 | + (hasPack ? HasPackFlag : 0U) | |
| 154 | + (isAFD ? AddressableForDependenciesFlag : 0U)) {} |
| 155 | + |
| 156 | + constexpr bool operator==(SILTypeProperties p) const { |
| 157 | + return Flags == p.Flags; |
| 158 | + } |
| 159 | + |
| 160 | + static constexpr SILTypeProperties forTrivial() { |
| 161 | + return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient}; |
| 162 | + } |
| 163 | + |
| 164 | + static constexpr SILTypeProperties forTrivialOpaque() { |
| 165 | + return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient, |
| 166 | + IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical, |
| 167 | + HasNoPack, IsAddressableForDependencies}; |
| 168 | + } |
| 169 | + |
| 170 | + static constexpr SILTypeProperties forRawPointer() { |
| 171 | + return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient, |
| 172 | + IsNotTypeExpansionSensitive, HasRawPointer}; |
| 173 | + } |
| 174 | + |
| 175 | + static constexpr SILTypeProperties forReference() { |
| 176 | + return {IsNotTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient, |
| 177 | + IsNotTypeExpansionSensitive, DoesNotHaveRawPointer, IsLexical}; |
| 178 | + } |
| 179 | + |
| 180 | + static constexpr SILTypeProperties forOpaque() { |
| 181 | + return {IsNotTrivial, IsNotFixedABI, IsAddressOnly, IsNotResilient, |
| 182 | + IsNotTypeExpansionSensitive, HasRawPointer, IsLexical, |
| 183 | + HasNoPack, IsAddressableForDependencies}; |
| 184 | + } |
| 185 | + |
| 186 | + static constexpr SILTypeProperties forResilient() { |
| 187 | + return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsResilient, |
| 188 | + IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical, |
| 189 | + HasNoPack, IsNotAddressableForDependencies}; |
| 190 | + } |
| 191 | + |
| 192 | + void addSubobject(SILTypeProperties other) { |
| 193 | + Flags |= other.Flags; |
| 194 | + } |
| 195 | + |
| 196 | + IsTrivial_t isTrivial() const { |
| 197 | + return IsTrivial_t((Flags & NonTrivialFlag) == 0); |
| 198 | + } |
| 199 | + HasRawPointer_t isOrContainsRawPointer() const { |
| 200 | + return HasRawPointer_t((Flags & HasRawPointerFlag) != 0); |
| 201 | + } |
| 202 | + IsFixedABI_t isFixedABI() const { |
| 203 | + return IsFixedABI_t((Flags & NonFixedABIFlag) == 0); |
| 204 | + } |
| 205 | + IsAddressOnly_t isAddressOnly() const { |
| 206 | + return IsAddressOnly_t((Flags & AddressOnlyFlag) != 0); |
| 207 | + } |
| 208 | + bool isLoadable() const { |
| 209 | + return !isAddressOnly(); |
| 210 | + } |
| 211 | + IsResilient_t isResilient() const { |
| 212 | + return IsResilient_t((Flags & ResilientFlag) != 0); |
| 213 | + } |
| 214 | + IsTypeExpansionSensitive_t isTypeExpansionSensitive() const { |
| 215 | + return IsTypeExpansionSensitive_t( |
| 216 | + (Flags & TypeExpansionSensitiveFlag) != 0); |
| 217 | + } |
| 218 | + IsInfiniteType_t isInfinite() const { |
| 219 | + return IsInfiniteType_t((Flags & InfiniteFlag) != 0); |
| 220 | + } |
| 221 | + IsLexical_t isLexical() const { |
| 222 | + return IsLexical_t((Flags & LexicalFlag) != 0); |
| 223 | + } |
| 224 | + HasPack_t isOrContainsPack() const { |
| 225 | + return HasPack_t((Flags & HasPackFlag) != 0); |
| 226 | + } |
| 227 | + IsAddressableForDependencies_t isAddressableForDependencies() const { |
| 228 | + return IsAddressableForDependencies_t( |
| 229 | + (Flags & AddressableForDependenciesFlag) != 0); |
| 230 | + } |
| 231 | + |
| 232 | + void setNonTrivial() { Flags |= NonTrivialFlag; } |
| 233 | + void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; } |
| 234 | + |
| 235 | + void setNonFixedABI() { Flags |= NonFixedABIFlag; } |
| 236 | + void setAddressOnly() { Flags |= AddressOnlyFlag; } |
| 237 | + void setTypeExpansionSensitive( |
| 238 | + IsTypeExpansionSensitive_t isTypeExpansionSensitive) { |
| 239 | + Flags = (Flags & ~TypeExpansionSensitiveFlag) | |
| 240 | + (isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0); |
| 241 | + } |
| 242 | + void setInfinite() { Flags |= InfiniteFlag; } |
| 243 | + void setLexical(IsLexical_t isLexical) { |
| 244 | + Flags = (Flags & ~LexicalFlag) | (isLexical ? LexicalFlag : 0); |
| 245 | + } |
| 246 | + void setHasPack() { Flags |= HasPackFlag; } |
| 247 | + void setAddressableForDependencies() { |
| 248 | + Flags |= AddressableForDependenciesFlag; |
| 249 | + } |
| 250 | +}; |
| 251 | + |
| 252 | +} // end namespace swift |
| 253 | + |
| 254 | +#endif |
0 commit comments