| Age | Commit message (Collapse) | Author |
|
This is neither a type nor a value. Simplifies `addStrLit` as well as
the many places that switch on `InternPool.Key`.
This is a partial revert of bec29b9e498e08202679aa29a45dab2a06a69a1e.
|
|
Being able to create a pointer to the non-opv sentinel means that these
types have to actually be stored.
|
|
This is a bit odd, because this value doesn't actually exist:
see #15909. This gets all the empty enum/union behavior tests passing.
Also adds an assertion to `Sema.analyzeBodyInner` which would have
helped figure out the issue here much more quickly.
|
|
|
|
Key.PtrType is now an extern struct so that hashing it can be done by
reinterpreting bytes directly. It also uses the same representation for
type_pointer Tag encoding and the Key. Accessing pointer attributes now
requires packed struct access, however, many operations are now a copy
of a u32 rather than several independent fields.
This function moves the top two most used Key variants - pointer types
and pointer values - to use a single-shot hash function that branches
for small keys instead of calling memcpy.
As a result, perf against merge-base went from 1.17x ± 0.04 slower to
1.12x ± 0.04 slower. After the pointer value hashing was changed, total
CPU instructions spent in memcpy went from 4.40% to 4.08%, and after
additionally improving pointer type hashing, it further decreased to
3.72%.
|
|
The Zig language allows the compiler to make this optimization
automatically. We should definitely make the compiler do that, and
revert this commit. However, that will not happen in this branch, and I
want to continue to explore achieving performance parity with
merge-base. So, this commit changes all InternPool parameters to be
passed by const pointer rather than by value.
I measured a 1.03x ± 0.03 speedup vs the previous commit compiling the
(set of passing) behavior tests. Against merge-base, this commit is
1.17x ± 0.04 slower, which is an improvement from the previous
measurement of 1.22x ± 0.02.
Related issue: #13510
Related issue: #14129
Related issue: #15688
|
|
|
|
|
|
|
|
This avoids memory management bugs with the previous implementation.
|
|
|
|
|
|
This is a particularly hot function, so we operate directly on encodings
rather than the more straightforward implementation of calling
`indexToKey`.
I measured this as 1.05 ± 0.04 times faster than the previous commit
with a ReleaseFast build against hello world (which includes std.debug
and formatted printing).
I also profiled the function and found that zigTypeTag() went from being
a major caller of `indexToKey` to being completely insignificant due to
being so fast.
|
|
|
|
|
|
Previously, there were types and values for inferred allocations and a
lot of special-case handling. Now, instead, the special casing is
limited to AIR instructions for these use cases.
Instead of storing data in Value payloads, the data is now stored in AIR
instruction data as well as the previously `void` value type of the
`unresolved_inferred_allocs` hash map.
|
|
|
|
|
|
Now, all types are migrated to use `InternPool`. The `Type.Tag` enum is
deleted in this commit.
|
|
This is now represented instead by a special `InternPool.Index.Tag` that
has no corresponding type/value.
|
|
|
|
|
|
One change worth noting in this commit is that `module.global_error_set`
is no longer kept strictly up-to-date. The previous code reserved
integer error values when dealing with error set types, but this is no
longer needed because the integer values are not needed for semantic
analysis unless `@errorToInt` or `@intToError` are used and therefore
may be assigned lazily.
|
|
Now pointer types are stored only in InternPool.
|
|
Now optional types are only stored in InternPool.
|
|
Also I moved `anyframe` from being represented by `SimpleType` to being
represented by the `none` tag of `anyframe_type` because most code wants
to handle these two types together.
|
|
|
|
Anonymous structs and anonymous tuples can be stored via a
only_possible_value tag because their type encodings, by definition,
will have every value specified, which can be used to populate the
fields slice in `Key.Aggregate`.
Also fix `isTupleOrAnonStruct`.
|
|
|
|
I'm seeing a new assertion trip: the call to `enumTagFieldIndex` in the
implementation of `@Type` is attempting to query the field index of an
union's enum tag, but the type of the enum tag value provided is not the
same as the union's tag type. Most likely this is a problem with type
coercion, since values are now typed.
Another problem is that I added some hacks in std.builtin because I
didn't see any convenient way to access them from Sema. That should
definitely be cleaned up before merging this branch.
|
|
These are now handled by the InternPool.
|
|
|
|
Unlike unions and structs, enums are actually *encoded* into the
InternPool directly, rather than using the SegmentedList trick. This
results in them being quite compact, and greatly improved the ergonomics
of using enum types throughout the compiler.
It did however require introducing a new concept to the InternPool which
is an "incomplete" item - something that is added to gain a permanent
Index, but which is then mutated in place. This was necessary because
enum tag values and tag types may reference the namespaces created by
the enum itself, which required constructing the namespace, decl, and
calling analyzeDecl on the decl, which required the decl value, which
required the enum type, which required an InternPool index to be
assigned and for it to be meaningful.
The API for updating enums in place turned out to be quite slick and
efficient - the methods directly populate pre-allocated arrays and
return the information necessary to output the same compilation errors
as before.
|
|
This introduces a string table into InternPool as well as a curious new
field called `maps` which is an array list of array hash maps with
void/void key/value.
Some types such as enums, structs, and unions need to store mappings
from field names to field index, or value to field index. In such cases,
they will store the underlying field names and values directly, relying
on one of these maps, stored separately, to provide lookup.
This allows the InternPool to be serialized via simple array copies,
omitting all the maps, which are only used for optimizing lookup based
on field name or field value.
When the InternPool is deserialized it can be loaded via simple array
copies, and then as a post-processing step the field name maps can be
generated as extra metadata that is tacked on.
This commit provides two encodings for enums - one when the integer tag
type is explicitly provided and one when it is not. This is simpler than
the previous setup, which has three encodings.
Previous sizes:
* EnumSimple: 40 bytes + 16 bytes per field
* EnumNumbered: 80 bytes + 24 bytes per field
* EnumFull: 184 bytes + 24 bytes per field
Sizes after this commit:
* type_enum_explicit: 24 bytes + 8 bytes per field
* type_enum_auto: 16 bytes + 4 bytes per field
|
|
|
|
|
|
|
|
|
|
Also modify coercion in Sema to be InternPool-aware by calling
getCoerced.
The unnecessary comptime logic in mod.intValue is deleted too
|
|
and use it to fix typeHasOnePossibleValue logic in two different places.
|
|
* make Sema.zirPtrType coerce the sentinel value against the element
type
* fix lazyAbiAlignment wrong result type
* typeHasOnePossibleValue no longer tries to create interned enum tag
value with integer zero, instead uses enum_field_index
* Type.ptr avoids trying to store typed null values into the intern
pool
|
|
|
|
|
|
This commit changes a lot of `*const Module` to `*Module` to make it
work, since accessing the integer tag type of an enum might need to
mutate the InternPool by adding a new integer type into it.
An alternate strategy would be to pre-heat the InternPool with the
integer tag type when creating an enum type, which would make it so that
intTagType could accept a const Module instead of a mutable one,
asserting that the InternPool already had the integer tag type.
|
|
|
|
This is a bit nasty, mainly because Type.onePossibleValue is now
errorable, which is a quite viral change.
|
|
|
|
|
|
|
|
This uses the data field to reference its pointer field type, which
allows for efficient and infallible access of a slice type's pointer
type.
|