Commit Graph

5 Commits

Author SHA1 Message Date
Michael Gottesman
e678f4979b [gardening] Add swift license headers to all files in ./unittests/Basic/*. 2017-02-09 22:02:42 -08:00
Michael Gottesman
3e002b7649 Use IsTriviallyCopyable instead of std::is_trivially_copyable to work around issues on Linux. 2016-01-07 13:16:59 -08:00
Michael Gottesman
328c146569 [ptrintenum] Cleanup equality method. 2016-01-07 13:14:21 -08:00
Michael Gottesman
1c5ffe6dea 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,
   };
2016-01-06 18:20:26 -08:00
Michael Gottesman
9fa6e31f9e [projection] Add a new data structure for use in NewProjection called PointerIntEnum.
PointerIntEnum is a more powerful PointerIntPair data structure. It uses
an enum with special cases to understand characteristics of the data and
then uses this information and the some tricks to be able to
represent:

1. Up to tagged bit number of pointer cases. The cases are stored inline.
2. Inline indices up to 4096.
3. Out of line indices > 4096.

It takes advantage of the trick that we use in the runtime already to
distinguish pointers from indices: namely that the zero page on modern
OSes do not allocate the zero page.

I made unittests for all of the operations so it is pretty well tested
out.

I am going to use this in a subsequent commit to compress projection in
the common case (the inline case) down to 1/3 of its size. The reason
why the inline case is common is that in most cases where projection is
used it will be targeting relative offsets in an array which are not
likely to be greater than a page. The mallocing of memory just enables
us to degrade gracefully.
2015-12-29 22:06:13 -06:00