aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
AgeCommit message (Collapse)Author
2025-11-20update deprecated ArrayListUnmanaged usage (#25958)Benjamin Jurk
2025-11-18cbe: fix big-endian unnatural integer bitcastMatthew Lugg
Integers with padding bits on big-endian targets cannot quite be bitcast with a trivial memcpy, because the padding bits (which are zext or sext) are the most-significant, so are at the *lowest* addresses. So to bitcast to something which doesn't have padding bits, we need to offset past the padding. The logic I've added here definitely doesn't handle all possibilities correctly; I think that would actually be quite complicated. However, it handles a common case, and so prevents the Zig compiler itself from being miscompiled on big-endian targets (hence fixing a bootstrapping problem on big-endian).
2025-11-15Legalize: implement soft-float legalizationsMatthew Lugg
A new `Legalize.Feature` tag is introduced for each float bit width (16/32/64/80/128). When e.g. `soft_f16` is enabled, all arithmetic and comparison operations on `f16` are converted to calls to the appropriate compiler_rt function using the new AIR tag `.legalize_compiler_rt_call`. This includes casts where the source *or* target type is `f16`, or integer<=>float conversions to or from `f16`. Occasionally, operations are legalized to blocks because there is extra code required; for instance, legalizing `@floatFromInt` where the integer type is larger than 64 bits requires calling an arbitrary-width integer conversion function which accepts a pointer to the integer, so we need to use `alloc` to create such a pointer, and store the integer there (after possibly zero-extending or sign-extending it). No backend currently uses these new legalizations (and as such, no backend currently needs to implement `.legalize_compiler_rt_call`). However, for testing purposes, I tried modifying the self-hosted x86_64 backend to enable all of the soft-float features (and implement the AIR instruction). This modified backend was able to pass all of the behavior tests (except for one `@mod` test where the LLVM backend has a bug resulting in incorrect compiler-rt behavior!), including the tests specific to the self-hosted x86_64 backend. `f16` and `f80` legalizations are likely of particular interest to backend developers, because most architectures do not have instructions to operate on these types. However, enabling *all* of these legalization passes can be useful when developing a new backend to hit the ground running and pass a good amount of tests more easily.
2025-11-12cbe: work around some miscompilationsMatthew Lugg
The changes to `codegen.c` are blatant hacks, but the problem they work around isn't a regression: it's an existing miscompilation. This branch happened to *expose* that miscompilation in more cases by changing how an incorrect result is *used*.
2025-11-12Air.Legalize: revert to loops for scalarizationsMatthew Lugg
I had tried unrolling the loops to avoid requiring the `vector_store_elem` instruction, but it's arguably a problem to generate O(N) code for an operation on `@Vector(N, T)`. In addition, that lowering emitted a lot of `.aggregate_init` instructions, which is itself a quite difficult operation to codegen. This requires reintroducing runtime vector indexing internally. However, I've put it in a couple of instructions which are intended only for use by `Air.Legalize`, named `legalize_vec_elem_val` (like `array_elem_val`, but for indexing a vector with a runtime-known index) and `legalize_vec_store_elem` (like the old `vector_store_elem` instruction). These are explicitly documented as *not* being emitted by Sema, so need only be implemented by backends if they actually use an `Air.Legalize.Feature` which emits them (otherwise they can be marked as `unreachable`).
2025-11-12compiler: spring cleaningMatthew Lugg
I started this diff trying to remove a little dead code from the C backend, but ended up finding a bunch of dead code sprinkled all over the place: * `packed` handling in the C backend which was made dead by `Legalize` * Representation of pointers to runtime-known vector indices * Handling for the `vector_store_elem` AIR instruction (now removed) * Old tuple handling from when they used the InternPool repr of structs * Straightforward unused functions * TODOs in the LLVM backend for features which Zig just does not support
2025-11-10cbe: kvx uses $-prefixed registersAlex Rønne Petersen
2025-11-01cbe: fix more MIPS register names in inline assemblyBingwu Zhang
2025-10-27feat: init x86_16 arch via CBEGasInfinity
2025-10-23std.builtin: add CallingConvention.sh_interruptAlex Rønne Petersen
Only supported in CBE.
2025-10-23std.builtin: add CallingConvention.microblaze_interruptAlex Rønne Petersen
Only supported in CBE.
2025-10-23std.builtin: add CallingConvention.msp430_interruptAlex Rønne Petersen
Supported by LLVM and CBE.
2025-10-23std.Target: add tags and info for alpha, hppa, microblaze, shAlex Rønne Petersen
2025-10-19compiler: add support for arc_interrupt calling conventionAlex Rønne Petersen
Only for use with the C backend at the moment.
2025-10-19cbe: fix MIPS register names in inline assemblyBingwu Zhang
Zig uses "rN" for MIPS register clobbers which are more ergonomic and easier to write (.rN vs. .@"$N"). However, GCC and Clang uses "$N". Bug: #25613 Signed-off-by: Bingwu Zhang <xtex@xtexx.eu.org>
2025-08-31std.fmt: delete deprecated APIsAndrew Kelley
std.fmt.Formatter -> std.fmt.Alt std.fmt.format -> std.Io.Writer.print
2025-08-29std.Io: delete GenericReaderAndrew Kelley
and delete deprecated alias std.io
2025-08-13Merge pull request #24674 from Justus2308/undef-shift-bitwiseMatthew Lugg
Sema: Improve comptime arithmetic undef handling
2025-08-13std.io.Writer.Allocating: rename getWritten() to written()Isaac Freund
This "get" is useless noise and was copied from FixedBufferWriter. Since this API has not yet landed in a release, now is a good time to make the breaking change to fix this.
2025-08-12Sema: Improve comptime arithmetic undef handlingJustus Klausecker
This commit expands on the foundations laid by https://github.com/ziglang/zig/pull/23177 and moves even more `Sema`-only functionality from `Value` to `Sema.arith`. Specifically all shift and bitwise operations, `@truncate`, `@bitReverse` and `@byteSwap` have been moved and adapted to the new rules around `undefined`. Especially the comptime shift operations have been basically rewritten, fixing many open issues in the process. New rules applied to operators: * `<<`, `@shlExact`, `@shlWithOverflow`, `>>`, `@shrExact`: compile error if any operand is undef * `<<|`, `~`, `^`, `@truncate`, `@bitReverse`, `@byteSwap`: return undef if any operand is undef * `&`, `|`: Return undef if both operands are undef, turn undef into actual `0xAA` bytes otherwise Additionally this commit canonicalizes the representation of aggregates with all-undefined members in the `InternPool` by disallowing them and enforcing the usage of a single typed `undef` value instead. This reduces the amount of edge cases and fixes a bunch of bugs related to partially undefined vecs. List of operations directly affected by this patch: * `<<`, `<<|`, `@shlExact`, `@shlWithOverflow` * `>>`, `@shrExact` * `&`, `|`, `~`, `^` and their atomic rmw + reduce pendants * `@truncate`, `@bitReverse`, `@byteSwap`
2025-08-11cbe: emit `nonstring` attributeJacob Young
Closes #24545
2025-07-22aarch64: add new from scratch self-hosted backendJacob Young
2025-07-20cbe: fix comptime-known packed unionsJacob Young
2025-07-16inline assembly: use typesAndrew Kelley
until now these were stringly typed. it's kinda obvious when you think about it.
2025-07-09CBE: avoid depending on std.io.Writer.countAndrew Kelley
2025-07-08C backend: fix bitcasting regressionAndrew Kelley
2025-07-07fix 32-bit compilationAndrew Kelley
2025-07-07std.fmt: fully remove format string from format methodsAndrew Kelley
Introduces `std.fmt.alt` which is a helper for calling alternate format methods besides one named "format".
2025-07-07std.fmt.format: use {t} for tag name rather than {s}Andrew Kelley
prevents footgun when formatted type changes from string to enum
2025-07-07compiler: update a bunch of format stringsAndrew Kelley
2025-07-07C backend: fix compilation errorsAndrew Kelley
2025-07-07cbe: reapply writer changesAndrew Kelley
2025-07-07C backend: prepare for mergeAndrew Kelley
2025-07-07compiler: fix a bunch of format stringsAndrew Kelley
2025-07-07compiler: fix a bunch of format stringsAndrew Kelley
2025-07-07compiler: upgrade various std.io API usageAndrew Kelley
2025-07-07compiler: update all instances of std.fmt.FormatterAndrew Kelley
2025-06-19Target: pass and use locals by pointer instead of by valueJacob Young
This struct is larger than 256 bytes and code that copies it consistently shows up in profiles of the compiler.
2025-06-15compiler: fix `@intFromFloat` safety checkmlugg
This safety check was completely broken; it triggered unchecked illegal behavior *in order to implement the safety check*. You definitely can't do that! Instead, we must explicitly check the boundaries. This is a tiny bit fiddly, because we need to make sure we do floating-point rounding in the correct direction, and also handle the fact that the operation truncates so the boundary works differently for min vs max. Instead of implementing this safety check in Sema, there are now dedicated AIR instructions for safety-checked intfromfloat (two instructions; which one is used depends on the float mode). Currently, no backend directly implements them; instead, a `Legalize.Feature` is added which expands the safety check, and this feature is enabled for all backends we currently test, including the LLVM backend. The `u0` case is still handled in Sema, because Sema needs to check for that anyway due to the comptime-known result. The old safety check here was also completely broken and has therefore been rewritten. In that case, we just check for 'abs(input) < 1.0'. I've added a bunch of test coverage for the boundary cases of `@intFromFloat`, both for successes (in `test/behavior/cast.zig`) and failures (in `test/cases/safety/`). Resolves: #24161
2025-06-15Legalize: make the feature set comptime-known in zig1Jacob Young
This allows legalizations to be added that aren't used by zig1 without affecting the size of zig1.
2025-06-12compiler: rework backend pipeline to separate codegen and linkmlugg
The idea here is that instead of the linker calling into codegen, instead codegen should run before we touch the linker, and after MIR is produced, it is sent to the linker. Aside from simplifying the call graph (by preventing N linkers from each calling into M codegen backends!), this has the huge benefit that it is possible to parallellize codegen separately from linking. The threading model can look like this: * 1 semantic analysis thread, which generates AIR * N codegen threads, which process AIR into MIR * 1 linker thread, which emits MIR to the binary The codegen threads are also responsible for `Air.Legalize` and `Air.Liveness`; it's more efficient to do this work here instead of blocking the main thread for this trivially parallel task. I have repurposed the `Zcu.Feature.separate_thread` backend feature to indicate support for this 1:N:1 threading pattern. This commit makes the C backend support this feature, since it was relatively easy to divorce from `link.C`: it just required eliminating some shared buffers. Other backends don't currently support this feature. In fact, they don't even compile -- the next few commits will fix them back up.
2025-06-06x86_64: add support for pie executablesJacob Young
2025-06-01compiler: implement better shuffle AIRmlugg
Runtime `@shuffle` has two cases which backends generally want to handle differently for efficiency: * One runtime vector operand; some result elements may be comptime-known * Two runtime vector operands; some result elements may be undefined The latter case happens if both vectors given to `@shuffle` are runtime-known and they are both used (i.e. the mask refers to them). Otherwise, if the result is not entirely comptime-known, we are in the former case. `Sema` now diffentiates these two cases in the AIR so that backends can easily handle them however they want to. Note that this *doesn't* really involve Sema doing any more work than it would otherwise need to, so there's not really a negative here! Most existing backends have their lowerings for `@shuffle` migrated in this commit. The LLVM backend uses new lowerings suggested by Jacob as ones which it will handle effectively. The x86_64 backend has not yet been migrated; for now there's a panic in there. Jacob will implement that before this is merged anywhere.
2025-06-01cbe: legalize safety instructions in non-zig1 buildsJacob Young
This is valid if the bootstrap dev env doesn't need to support runtime safety. Another solution can always be implemented if needs change.
2025-05-31cbe: implement `stdbool.h` reserved identifiersJacob Young
Also remove the legalize pass from zig1.
2025-05-31Sema: remove `all_vector_instructions` logicJacob Young
Backends can instead ask legalization on a per-instruction basis.
2025-05-31Legalize: implement scalarization of binary operationsJacob Young
2025-05-29Legalize: introduce a new pass before livenessJacob Young
Each target can opt into different sets of legalize features. By performing these transformations before liveness, instructions that become unreferenced will have up-to-date liveness information.
2025-05-27compiler: tlv pointers are not comptime-knownmlugg
Pointers to thread-local variables do not have their addresses known until runtime, so it is nonsensical for them to be comptime-known. There was logic in the compiler which was essentially attempting to treat them as not being comptime-known despite the pointer being an interned value. This was a bit of a mess, the check was frequent enough to actually show up in compiler profiles, and it was very awkward for backends to deal with, because they had to grapple with the fact that a "constant" they were lowering might actually require runtime operations. So, instead, do not consider these pointers to be comptime-known in *any* way. Never intern such a pointer; instead, when the address of a threadlocal is taken, emit an AIR instruction which computes the pointer at runtime. This avoids lots of special handling for TLVs across basically all codegen backends; of all somewhat-functional backends, the only one which wasn't improved by this change was the LLVM backend, because LLVM pretends this complexity around threadlocals doesn't exist. This change simplifies Sema and codegen, avoids a potential source of bugs, and potentially improves Sema performance very slightly by avoiding a non-trivial check on a hot path.
2025-05-18compiler: refactor `Zcu.File` and path representationmlugg
This commit makes some big changes to how we track state for Zig source files. In particular, it changes: * How `File` tracks its path on-disk * How AstGen discovers files * How file-level errors are tracked * How `builtin.zig` files and modules are created The original motivation here was to address incremental compilation bugs with the handling of files, such as #22696. To fix this, a few changes are necessary. Just like declarations may become unreferenced on an incremental update, meaning we suppress analysis errors associated with them, it is also possible for all imports of a file to be removed on an incremental update, in which case file-level errors for that file should be suppressed. As such, after AstGen, the compiler must traverse files (starting from analysis roots) and discover the set of "live files" for this update. Additionally, the compiler's previous handling of retryable file errors was not very good; the source location the error was reported as was based only on the first discovered import of that file. This source location also disappeared on future incremental updates. So, as a part of the file traversal above, we also need to figure out the source locations of imports which errors should be reported against. Another observation I made is that the "file exists in multiple modules" error was not implemented in a particularly good way (I get to say that because I wrote it!). It was subject to races, where the order in which different imports of a file were discovered affects both how errors are printed, and which module the file is arbitrarily assigned, with the latter in turn affecting which other files are considered for import. The thing I realised here is that while the AstGen worker pool is running, we cannot know for sure which module(s) a file is in; we could always discover an import later which changes the answer. So, here's how the AstGen workers have changed. We initially ensure that `zcu.import_table` contains the root files for all modules in this Zcu, even if we don't know any imports for them yet. Then, the AstGen workers do not need to be aware of modules. Instead, they simply ignore module imports, and only spin off more workers when they see a by-path import. During AstGen, we can't use module-root-relative paths, since we don't know which modules files are in; but we don't want to unnecessarily use absolute files either, because those are non-portable and can make `error.NameTooLong` more likely. As such, I have introduced a new abstraction, `Compilation.Path`. This type is a way of representing a filesystem path which has a *canonical form*. The path is represented relative to one of a few special directories: the lib directory, the global cache directory, or the local cache directory. As a fallback, we use absolute (or cwd-relative on WASI) paths. This is kind of similar to `std.Build.Cache.Path` with a pre-defined list of possible `std.Build.Cache.Directory`, but has stricter canonicalization rules based on path resolution to make sure deduplicating files works properly. A `Compilation.Path` can be trivially converted to a `std.Build.Cache.Path` from a `Compilation`, but is smaller, has a canonical form, and has a digest which will be consistent across different compiler processes with the same lib and cache directories (important when we serialize incremental compilation state in the future). `Zcu.File` and `Zcu.EmbedFile` both contain a `Compilation.Path`, which is used to access the file on-disk; module-relative sub paths are used quite rarely (`EmbedFile` doesn't even have one now for simplicity). After the AstGen workers all complete, we know that any file which might be imported is definitely in `import_table` and up-to-date. So, we perform a single-threaded graph traversal; similar to what `resolveReferences` plays for `AnalUnit`s, but for files instead. We figure out which files are alive, and which module each file is in. If a file turns out to be in multiple modules, we set a field on `Zcu` to indicate this error. If a file is in a different module to a prior update, we set a flag instructing `updateZirRefs` to invalidate all dependencies on the file. This traversal also discovers "import errors"; these are errors associated with a specific `@import`. With Zig's current design, there is only one possible error here: "import outside of module root". This must be identified during this traversal instead of during AstGen, because it depends on which module the file is in. I tried also representing "module not found" errors in this same way, but it turns out to be much more useful to report those in Sema, because of use cases like optional dependencies where a module import is behind a comptime-known build option. For simplicity, `failed_files` now just maps to `?[]u8`, since the source location is always the whole file. In fact, this allows removing `LazySrcLoc.Offset.entire_file` completely, slightly simplifying some error reporting logic. File-level errors are now directly built in the `std.zig.ErrorBundle.Wip`. If the payload is not `null`, it is the message for a retryable error (i.e. an error loading the source file), and will be reported with a "file imported here" note pointing to the import site discovered during the single-threaded file traversal. The last piece of fallout here is how `Builtin` works. Rather than constructing "builtin" modules when creating `Package.Module`s, they are now constructed on-the-fly by `Zcu`. The map `Zcu.builtin_modules` maps from digests to `*Package.Module`s. These digests are abstract hashes of the `Builtin` value; i.e. all of the options which are placed into "builtin.zig". During the file traversal, we populate `builtin_modules` as needed, so that when we see this imports in Sema, we just grab the relevant entry from this map. This eliminates a bunch of awkward state tracking during construction of the module graph. It's also now clearer exactly what options the builtin module has, since previously it inherited some options arbitrarily from the first-created module with that "builtin" module! The user-visible effects of this commit are: * retryable file errors are now consistently reported against the whole file, with a note pointing to a live import of that file * some theoretical bugs where imports are wrongly considered distinct (when the import path moves out of the cwd and then back in) are fixed * some consistency issues with how file-level errors are reported are fixed; these errors will now always be printed in the same order regardless of how the AstGen pass assigns file indices * incremental updates do not print retryable file errors differently between updates or depending on file structure/contents * incremental updates support files changing modules * incremental updates support files becoming unreferenced Resolves: #22696