aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
AgeCommit message (Collapse)Author
2025-07-13LLVM backend: fixesAndrew Kelley
* delete dead code * don't access stack trace too early * revert unintended edit
2025-07-13Do not store StackTrace typeAli Cheraghi
2025-07-13LLVM: Move pt field from Object to NavGenantlilja
* LLVM: Pass correct tid to emit * Store stack trace type in Zcu * Don't use pt.errorIntType in LLVM backend
2025-07-07compiler: upgrade various std.io API usageAndrew Kelley
2025-07-07std.fmt: breaking API changesAndrew Kelley
added adapter to AnyWriter and GenericWriter to help bridge the gap between old and new API make std.testing.expectFmt work at compile-time std.fmt no longer has a dependency on std.unicode. Formatted printing was never properly unicode-aware. Now it no longer pretends to be. Breakage/deprecations: * std.fs.File.reader -> std.fs.File.deprecatedReader * std.fs.File.writer -> std.fs.File.deprecatedWriter * std.io.GenericReader -> std.io.Reader * std.io.GenericWriter -> std.io.Writer * std.io.AnyReader -> std.io.Reader * std.io.AnyWriter -> std.io.Writer * std.fmt.format -> std.fmt.deprecatedFormat * std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape * std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape * std.fmt.fmtSliceHexLower -> {x} * std.fmt.fmtSliceHexUpper -> {X} * std.fmt.fmtIntSizeDec -> {B} * std.fmt.fmtIntSizeBin -> {Bi} * std.fmt.fmtDuration -> {D} * std.fmt.fmtDurationSigned -> {D} * {} -> {f} when there is a format method * format method signature - anytype -> *std.io.Writer - inferred error set -> error{WriteFailed} - options -> (deleted) * std.fmt.Formatted - now takes context type explicitly - no fmt string
2025-07-08Merge pull request #24362 (remove async, await, usingnamespace)Andrew Kelley
remove `async` and `await` keywords; remove `usingnamespace`
2025-07-08llvm: Revert #17963 (workaround for #16392)Alex Rønne Petersen
2025-07-07zig fmtAndrew Kelley
2025-07-07remove `async` and `await` keywordsAndrew Kelley
Also remove `@frameSize`, closing #3654. While the other machinery might remain depending on #23446, it is settled that there will not be `async`/ `await` keywords in the language.
2025-07-07llvm: Use emulated TLS when appropriate for the targetAlex Rønne Petersen
Closes #24236.
2025-07-02compiler: change canonical path for backend ABI source filesAndrew Kelley
2025-07-02compiler: delete arm backendAndrew Kelley
this backend was abandoned before it was completed, and it is not worth salvaging.
2025-07-02compiler: delete aarch64 backendAndrew Kelley
this backend was abandoned before it was completed, and it is not worth salvaging.
2025-07-01llvm: Disable the machine outliner pass on RISC-VAlex Rønne Petersen
2025-07-01llvm: Fix alignment of by-ref ptr_elem_val and slice_elem_valAlex Rønne Petersen
2025-06-23remove `spirv` cpu archAli Cheraghi
2025-06-19x86_64: increase passing test coverage on windowsJacob Young
Now that codegen has no references to linker state this is much easier. Closes #24153
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-12x86_64: remove air references from mirJacob Young
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-12link: divorce LLD from the self-hosted linkersmlugg
Similar to the previous commit, this commit untangles LLD integration from the self-hosted linkers. Despite the big network of functions which were involved, it turns out what was going on here is quite simple. The LLD linking logic is actually very self-contained; it requires a few flags from the `link.File.OpenOptions`, but that's really about it. We don't need any of the mutable state on `Elf`/`Coff`/`Wasm`, for instance. There was some legacy code trying to handle support for using self-hosted codegen with LLD, but that's not a supported use case, so I've just stripped it out. For now, I've just pasted the logic for linking the 3 targets we currently support using LLD for into this new linker implementation, `link.Lld`; however, it's almost certainly possible to combine some of the logic and simplify this file a bit. But to be honest, it's not actually that bad right now. This commit ends up eliminating the distinction between `flush` and `flushZcu` (formerly `flushModule`) in linkers, where the latter previously meant something along the lines of "flush, but if you're going to be linking with LLD, just flush the ZCU object file, don't actually link"?. The distinction here doesn't seem like it was properly defined, and most linkers seem to treat them as essentially identical anyway. Regardless, all calls to `flushZcu` are gone now, so it's deleted -- one `flush` to rule them all! The end result of this commit and the preceding one is that LLVM and LLD fit into the pipeline much more sanely: * If we're using LLVM for the ZCU, that state is on `zcu.llvm_object` * If we're using LLD to link, then the `link.File` is a `link.Lld` * Calls to "ZCU link functions" (e.g. `updateNav`) lower to calls to the LLVM object if it's available, or otherwise to the `link.File` if it's available (neither is available under `-fno-emit-bin`) * After everything is done, linking is finalized by calling `flush` on the `link.File`; for `link.Lld` this invokes LLD, for other linkers it flushes self-hosted linker state There's one messy thing remaining, and that's how self-hosted function codegen in a ZCU works; right now, we process AIR with a call sequence something like this: * `link.doTask` * `Zcu.PerThread.linkerUpdateFunc` * `link.File.updateFunc` * `link.Elf.updateFunc` * `link.Elf.ZigObject.updateFunc` * `codegen.generateFunction` * `arch.x86_64.CodeGen.generate` So, we start in the linker, take a scenic detour through `Zcu`, go back to the linker, into its implementation, and then... right back out, into code which is generic over the linker implementation, and then dispatch on the *backend* instead! Of course, within `arch.x86_64.CodeGen`, there are some more places which switch on the `link` implementation being used. This is all pretty silly... so it shall be my next target.
2025-06-12compiler: slightly untangle LLVM from the linkersmlugg
The main goal of this commit is to make it easier to decouple codegen from the linkers by being able to do LLVM codegen without going through the `link.File`; however, this ended up being a nice refactor anyway. Previously, every linker stored an optional `llvm.Object`, which was populated when using LLVM for the ZCU *and* linking an output binary; and `Zcu` also stored an optional `llvm.Object`, which was used only when we needed LLVM for the ZCU (e.g. for `-femit-llvm-bc`) but were not emitting a binary. This situation was incredibly silly. It meant there were N+1 places the LLVM object might be instead of just 1, and it meant that every linker had to start a bunch of methods by checking for an LLVM object, and just dispatching to the corresponding method on *it* instead if it was not `null`. Instead, we now always store the LLVM object on the `Zcu` -- which makes sense, because it corresponds to the object emitted by, well, the Zig Compilation Unit! The linkers now mostly don't make reference to LLVM. `Compilation` makes sure to emit the LLVM object if necessary before calling `flush`, so it is ready for the linker. Also, all of the `link.File` methods which act on the ZCU -- like `updateNav` -- now check for the LLVM object in `link.zig` instead of in every single individual linker implementation. Notably, the change to LLVM emit improves this rather ludicrous call chain in the `-fllvm -flld` case: * Compilation.flush * link.File.flush * link.Elf.flush * link.Elf.linkWithLLD * link.Elf.flushModule * link.emitLlvmObject * Compilation.emitLlvmObject * llvm.Object.emit Replacing it with this one: * Compilation.flush * llvm.Object.emit ...although we do currently still end up in `link.Elf.linkWithLLD` to do the actual linking. The logic for invoking LLD should probably also be unified at least somewhat; I haven't done that in this commit.
2025-06-06x86_64: add support for pie executablesJacob Young
2025-06-05std.Target: Introduce Cpu convenience functions for feature tests.Alex Rønne Petersen
Before: * std.Target.arm.featureSetHas(target.cpu.features, .has_v7) * std.Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx, .cmov }) * std.Target.wasm.featureSetHasAll(target.cpu.features, .{ .atomics, .bulk_memory }) After: * target.cpu.has(.arm, .has_v7) * target.cpu.hasAny(.x86, &.{ .sse, .avx, .cmov }) * target.cpu.hasAll(.wasm, &.{ .atomics, .bulk_memory })
2025-06-04valgrind: Add riscv64-linux support.Alex Rønne Petersen
This appeared in Valgrind 3.25.0.
2025-06-01compiler: combine `@intCast` safety checksmlugg
`castTruncatedData` was a poorly worded error (all shrinking casts "truncate bits", it's just that we assume those bits to be zext/sext of the other bits!), and `negativeToUnsigned` was a pointless distinction which forced the compiler to emit worse code (since two separate safety checks were required for casting e.g. 'i32' to 'u16') and wasn't even implemented correctly. This commit combines those safety panics into one function, `integerOutOfBounds`. The name maybe isn't perfect, but that's not hugely important; what matters is the new default message, which is clearer than the old ones: "integer does not fit in destination type".
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-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-20Merge pull request #23836 from mlugg/incr-fixesMatthew Lugg
Incremental fixes, refactor `Zcu.File`
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
2025-05-17x86_64: rewrite scalar `<<|`Jacob Young
Closes #23035
2025-05-12llvm: Fix a bunch of volatile semantics violations.Alex Rønne Petersen
Also fix some cases where we were being overzealous in applying volatile.
2025-05-12llvm: Don't set nonnull attribute on pointers in non-generic address spaces.Alex Rønne Petersen
LLVM considers null pointers to be valid for such address spaces.
2025-05-12llvm: Don't set nonnull attribute on allowzero slices.Alex Rønne Petersen
2025-05-12llvm: Set null_pointer_is_valid attribute when accessing allowzero pointers.Alex Rønne Petersen
This informs optimization passes that they shouldn't assume that a load from a null pointer invokes undefined behavior. Closes #15816.
2025-05-03std.Target: Add Cpu.Arch.or1k and basic target info.Alex Rønne Petersen
2025-05-02inline assembly: implement gcc's "%=" syntaxsamy007
2025-05-01wasm-c-abi: llvm fix struct handling + reorganizePavel Verigo
I changed to `wasm/abi.zig`, this design is certainly better than the previous one. Still there is some conflict of interest between llvm and self-hosted backend, better design will appear when abi tests will be tested with self-hosted. Resolves: #23304 Resolves: #23305
2025-04-28Merge pull request #23698 from alexrp/goff-xcoff-stubsAlex Rønne Petersen
`link`: Stub out GOFF/XCOFF linker code based on LLVM
2025-04-28std.Target: Remove Os.Tag.elfiamcu.Alex Rønne Petersen
The last Intel Quark MCU was released in 2015. Quark was announced to be EOL in 2019, and stopped shipping entirely in 2022. The OS tag was only meaningful for Intel's weird fork of Linux 3.8.7 with a special ABI that differs from the regular i386 System V ABI; beyond that, the CPU itself is just a plain old P54C (i586). We of course keep support for the CPU itself, just not Intel's Linux fork.
2025-04-27Merge pull request #22605 from dweiller/memmoveAndrew Kelley
add `@memmove` builtin
2025-04-27llvm: Fix data layout string for s390x-zos.Alex Rønne Petersen
2025-04-26std.Target: Remove Abi.gnuilp32.Alex Rønne Petersen
* This has not seen meaningful development for about a decade. * The Linux kernel port was never upstreamed. * The glibc port was never upstreamed. * GCC 15.1 recently deprecated support it. It may still make sense to support an ILP32 ABI on AArch64 more broadly (which we already have the Abi.ilp32 tag for), but, to the extent that it even existed in any "official" sense, the *GNU* ILP32 ABI is certainly dead.
2025-04-26compiler: add @memmove builtindweiller
2025-04-09compiler: Allow using LLVM's SPIR-V backend.Alex Rønne Petersen