This PR enables all incremental tests under the `test/incremental` directory, except one: `change_exports`, which is currently ignored as it requires a non-trivial amount of work on the linker, since we do not currently support exporting data symbols.
To enable the other tests, the following fixes were needed:
1. `src/link/Wasm.zig`: instead of chasing function type through Nav, get it directly.
2. `src/target.zig`: `.panic_fn` appears to work fine with the wasm backend.
3. `src/codegen/wasm/CodeGen.zig`: there was a liveness related bug that caused some `ArenaAllocator` code to crash the backend.
More info on (3), the liveness and local reuse code in the backend for years in unfinished state. For example there is currently no branch merging and reuse happens only when inst die in same block level. I initially considered doing a large refactor to implement everything correctly, but aborted due to its sheer size and currently! no clear idea about how to do this efficiently.
Instead, I fixed the bug with minimal changes and removed useless code, keeping the old solution otherwise intact.
The main goal here is to make incremental compilation work a bit better.
I also slightly expanded some `std.zig.llvm.Builder` APIs so that we
don't need to pointlessly create new `Global`s whenever e.g. a function
turns into a variable or vice versa.
Also, lean into aliases for exports! If we just use aliases for every
export, everything becomes simpler. Besides, we can't just go around
renaming the globals of `Nav`s: the export could disappear on a future
update, in which case we'd have to somehow revert that change, which is
easier said than done.
Avoid directly querying `Builder.Type`s in favour of `lowerType` calls
in a couple of places. The idea here is to avoid querying state stored
in the `Builder` to try and move towards a world where codegen
(essentially the logic in `codegen.llvm.FuncGen`) can happen on a
separate thread to "linking" (which actually interacts with shared state
on `codegen.llvm.Object` and `std.zig.llvm.Builder`).
Don't clear the `Builder` state during `emit`; this is clearly
incompatible with incremental compilation. With that line of code
removed, incremental compilation is actually already somewhat functional
with the LLVM backend.
Also, don't use `c_uint` for source location state---I have no idea
where this came from but it definitely isn't correct.
Also, notably, remove `Air.value`! The `onePossibleValue` check was
actually dead code, because it is a bug if Sema ever emits code which
considers a value of OPV type to be runtime-known---and at that point
`Air.value` is just a thin wrapper around `Air.Ref.toInterned`.
LLVM is gradually transitioning from the `getelementptr` instruction to
a new `ptradd` instruction. The latter instruction doesn't actually
exist yet, but for now, LLVM is considering `getelementptr i8` to be
equivalent. LLVM is already internally canonicalizing `getelementptr`
usages to this pattern in many cases, and it's far easier for us to emit
that, so... let's do so!
For runtime indexing this does sometimes require an explicit
multiplication to scale an index to a byte offset. The helper function
`llvm.FuncGen.ptraddScaled` makes this common pattern more convenient.
A particularly nice side effect from this is that after removing some
dead code (left over from before we made all `struct`s etc by-ref), it
has eliminated the need to maintain that nasty mapping between Zig field
indices and LLVM field indices. `FuncGen` no longer cares at all how
aggregate types are lowered!
Slices are still by-val at least for now, but they never lived in that
mapping because their structure is simple and consistent (they always
have a pointer at field index 0 and a usize at field index 1, with no
explicit padding necessary).
This mostly just moves `FuncGen` into its own file, but there are also a
few more cleanups, such as removing `NavGen` (it no longer served any
purpose) and slightly simplifying the logic for emitting codegen errors.
- x86_64: Implement @cVaStart for Win64
- x86_64: Implement @cVaArg for Win64
- x86_64: Duplicate floating point register args equivalent integer registers when calling variadic functions on Win64
- tests: Enable var_args tests for the self-hosted backend on windows
- tests: Add var_args test for floating point arguments
`switch` statements on types >128bits are now lowered to conditionals.
This is necessary because Zig lowers integers with more than 128 bits to
bigints, which are not 'native' integers and thus cannot be used as case
values.
128-bit integers get special treatment because Zig will emit actual 128bit
ints if they are supported by the target. They still *may* be lowered to
bigints though, e.g. for 32-bit targets or MSVC. To solve this, this commit
adds a bunch of switch macros to `zig.h` which will either resolve to an
actual `switch` statement or to conditionals. The `if` statements this
approach can generate are not as optimal as they could be but I think this
is a good trade-off since the generated `switch` statements are still the
same as the ones generated for smaller integers. Also the macros result
in pretty readable code.
I went over a bunch of calls to `std.zig.llvm.Builder.{load,store}` and
added correct alignments where we previously passed the default
alignment. This fixes some miscompilations, particularly when using
underaligned pointers or *overaligned* slices. I have definitely missed
some cases, but it's better to get some fixes in than for this to sit in
a `git stash` forever.
Resolves: https://codeberg.org/ziglang/zig/issues/31473
Resolves: https://codeberg.org/ziglang/zig/issues/30566
It was fairly straightforward to at least theoretically handle
incremental updates to the fields of an enum type correctly: we just
build a new set of instructions, and `std.zig.llvm.Builder` already
knows how to replace the old function body with the new one when we call
`WipFunction.finish`.
Also tightened a few error sets.
I've realised that the cause of at least some of our weird CI flakiness
was a bug in how `Nav` values were resolved. Consider this scenario: the
frontend resolves the type of a `Nav`, and then sends a function to the
backend, which requires the backend to lower a pointer to that `Nav`.
The backend calls `InternPool.getNav` to determine the `Nav`'s type.
However, this races with the frontend resolving the *value* of that
`Nav`. This involves writing separately to two fields, `bits` and
`type_or_value`. If only one of these changes is observed, then the
backend will incorrectly interpret the type as the value or vice versa,
leading to a crash or even a miscompilation. (Of course, there's also
the straightforward issue that the racing loads were non-atomic, making
them illegal).
The only good solution to this was to make `Nav` 4 bytes bigger, giving
it separate `type` and `value` fields. In theory that's a quite small
change, but it ended up having a bunch of nice consequences which led to
this diff being a bit bulkier than expected:
* `Nav.Repr.Bits` was simplified, because it no longer has to track
"resolution status": we can use `.none` for that. This frees up some
bits to make things more consistent between the "type resolved" and
"fully resolved" states.
* This consistency allowed the `Nav.status` union to be replaced with a
simpler field `Nav.resolved`, which is a bit nicer to work with.
* Most of the "getter" functions were able to be removed from `Nav`
because the state they were fetching had been moved to simple fields
on `Nav.resolved`.
* There were still a handful of free bits in `Nav.Repr.Bits`, which
could be used to represent the "const" and "threadlocal" flags rather
than these being stored on `Key.Extern` and `Key.Variable`. This is a
bit more convenient for linkers.
* With those bits gone, `Key.Variable` is a trivial wrapper around a
type and an initial value, and the fact that a declaration is mutable
can be represented solely through the "const" flag. Therefore,
`Key.Variable` no longer served a purpose, and could be eliminated
entirely in favour of storing the variable's initial value directly in
the "value" field of the `Nav`.
So, I'm quite pleased with this refactor! But anyway, regarding the bug
fix which actually motivated this: if I've done my job correctly, this
should solve some crashes, such as these (which were what tipped me off
to this bug in the first place):
https://codeberg.org/ziglang/zig/actions/runs/2306/jobs/7/attempt/1https://codeberg.org/ziglang/zig/actions/runs/2173/jobs/6/attempt/1
...and, who knows, perhaps even the random SIGSEGVs we've seen on some
targets! Probably not, but one can hope.
This PR started as addressing the long-standing TODO above `buildOpcode`:
/// TODO: deprecated, should be split up per tag.
The code around this area was written a long time ago and has effectively
become a legacy approach. When I started doing semi-occasional work for
bringing >128-bit integer operations to the wasm backend, which is
the last big missing piece of this backend, this design became annoying.
While thinking about how to support that work, and also how vector unrolling
should be handled (in cases where we do not rely purely on the legalize pass),
I decided to do some architectural changes were needed.
The first step is removing helpers like `intBinOp`, `floatBinOp`, `UnOp`, etc.
They do not really capture all operations and resulted in a lot of small
pieces of code trying to artificially unify different ops.
Instead, the direction taken here is similar to `Sema/arith.zig`, introduce
backend-oriented helpers such as `int*Op*Scalar` and `float*Op*` that operate
purely in backend structures without referencing AIR at all.
Additionally, the idea of introducing dedicated `IntType` and `FloatType`
types was chosen. Using `Type` from Sema inside the backend is awkward,
especially when strange or temporary types are needed. Creating them through
`PerThread` is also undesirable since the backend strives to not modify
`InternPool`. This goal is not fully achieved yet, some parts still require
changes, and `InternPool` type formatting still requires `pt` for error
reporting.
This PR also enables legalize passes for some packed operations. The previous
code in this area was buggy, and given the current state of the backend,
relying on legalization is simpler.
Finally, this PR disables one behavior test: `atomicrmw` with floats. The test
seems to only run the non-concurrency path, because it would crash otherwise,
and since we do not currently run behavior tests for the self-hosted backend
with concurrency or atomics enabled, it does not provide meaningful coverage yet.
In summary, this refactor reworks instruction selection in the wasm backend
to simplify the code and make future work, especially adding big integer
support.
Since packed containers are now represented by `bitpack` and can't include
pointers anymore this has become a very easy change to make. This commit
largely just reuses the logic already in place for integers.
Also fixes a small bug where captures-by-ref of errors wouldn't cause a
compile error for regular switch statements. There was already an astgen
error in place for error handling switch statements (`switch_block_err_union`)
capturing their error by reference.