Commits

Michael Gottesman committed 1c5ffe6dead
Change PointerIntEnum to a new better representation. The big differences here are that: 1. We no longer use the 4096 trick. 2. Now we store all indices inline so no mallocing is required and the value is trivially copyable. We allow for much larger indices to be stored inline which makes having an unrepresentable index a much smaller issue. For instance on a 32 bit platform, in NewProjection, we are able to represent an index of up to (1 << 26) - 1, which should be more than enough to handle any interesting case. 3. We can now have up to 7 ptr cases and many more index cases (with each extra bit needed to represent the index cases lowering the representable range of indices). The whole data structure is much simpler and easier to understand as a bonus. A high level description of the ADT is as follows: 1. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are not all set to 1 represent an enum with a pointer case. This means that one can have at most ((1 << num_tagged_bits(T*)) - 2) enum cases associated with pointers. 2. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are all set is either an invalid PointerIntEnum or an index. 3. A PointerIntEnum with all bits set is an invalid PointerIntEnum. 4. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are all set but for which the upper bits are not all set is an index enum. The case bits for the index PointerIntEnum are stored in bits [num_tagged_bits(T*), num_tagged_bits(T*) + num_index_case_bits]. Then the actual index is stored in the remaining top bits. For the case in which this is used in swift currently, we use 3 index bits meaning that on a 32 bit system we have 26 bits for representing indices meaning we can represent indices up to 67_108_862. Any index larger than that will result in an invalid PointerIntEnum. On 64 bit we have many more bits than that. By using this representation, we can make PointerIntEnum a true value type that is trivially constructable and destructable without needing to malloc memory. In order for all of this to work, the user of this needs to construct an enum with the appropriate case structure that allows the data structure to determine what cases are pointer and which are indices. For instance the one used by Projection in swift is: enum class NewProjectionKind : unsigned { // PointerProjectionKinds Upcast = 0, RefCast = 1, BitwiseCast = 2, FirstPointerKind = Upcast, LastPointerKind = BitwiseCast, // This needs to be set to ((1 << num_tagged_bits(T*)) - 1). It // represents the first NonPointerKind. FirstIndexKind = 7, // Index Projection Kinds Struct = PointerIntEnumIndexKindValue<0, EnumTy>::value, Tuple = PointerIntEnumIndexKindValue<1, EnumTy>::value, Index = PointerIntEnumIndexKindValue<2, EnumTy>::value, Class = PointerIntEnumIndexKindValue<3, EnumTy>::value, Enum = PointerIntEnumIndexKindValue<4, EnumTy>::value, LastIndexKind = Enum, };