aboutsummaryrefslogtreecommitdiff
path: root/src/Liveness.zig
AgeCommit message (Collapse)Author
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-04-26compiler: add @memmove builtindweiller
2025-01-31Sema: introduce all_vector_instructions backend featureJacob Young
Sema is arbitrarily scalarizing some operations, which means that when I try to implement vectorized versions of those operations in a backend, they are impossible to test due to Sema not producing them. Now, I can implement them and then temporarily enable the new feature for that backend in order to test them. Once the backend supports all of them, the feature can be permanently enabled. This also deletes the Air instructions `int_from_bool` and `int_from_ptr`, which are just bitcasts with a fixed result type, since changing `un_op` to `ty_op` takes up the same amount of memory.
2025-01-30compiler: add `intcast_safe` AIR instructionmlugg
This instruction is like `intcast`, but includes two safety checks: * Checks that the int is in range of the destination type * If the destination type is an exhaustive enum, checks that the int is a named enum value This instruction is locked behind the `safety_checked_instructions` backend feature; if unsupported, Sema will emit a fallback, as with other safety-checked instructions. This instruction is used to add a missing safety check for `@enumFromInt` truncating bits. This check also has a fallback for backends which do not yet support `safety_checked_instructions`. Resolves: #21946
2025-01-16x86_64: implement switch jump tablesJacob Young
2025-01-16x86_64: rewriteJacob Young
2024-11-24dwarf: fix stepping through an inline loop containing one statementJacob Young
Previously, stepping from the single statement within the loop would always exit the loop because all of the code unrolled from the loop is associated with the same line and treated by the debugger as one line.
2024-10-04remove `@fence` (#21585)David Rubin
closes #11650
2024-09-12Replace deprecated default initializations with decl literalsLinus Groh
2024-09-01compiler: implement labeled switch/continuemlugg
2024-09-01Air: add explicit `repeat` instruction to repeat loopsmlugg
This commit introduces a new AIR instruction, `repeat`, which causes control flow to move back to the start of a given AIR loop. `loop` instructions will no longer automatically perform this operation after control flow reaches the end of the body. The motivation for making this change now was really just consistency with the upcoming implementation of #8220: it wouldn't make sense to have this feature work significantly differently. However, there were already some TODOs kicking around which wanted this feature. It's useful for two key reasons: * It allows loops over AIR instruction bodies to loop precisely until they reach a `noreturn` instruction. This allows for tail calling a few things, and avoiding a range check on each iteration of a hot path, plus gives a nice assertion that validates AIR structure a little. This is a very minor benefit, which this commit does apply to the LLVM and C backends. * It should allow for more compact ZIR and AIR to be emitted by having AstGen emit `repeat` instructions more often rather than having `continue` statements `break` to a `block` which is *followed* by a `repeat`. This is done in status quo because `repeat` instructions only ever cause the direct parent block to repeat. Now that AIR is more flexible, this flexibility can be pretty trivially extended to ZIR, and we can then emit better ZIR. This commit does not implement this. Support for this feature is currently regressed on all self-hosted native backends, including x86_64. This support will be added where necessary before this branch is merged.
2024-08-27compiler: implement `@branchHint`, replacing `@setCold`mlugg
Implements the accepted proposal to introduce `@branchHint`. This builtin is permitted as the first statement of a block if that block is the direct body of any of the following: * a function (*not* a `test`) * either branch of an `if` * the RHS of a `catch` or `orelse` * a `switch` prong * an `or` or `and` expression It lowers to the ZIR instruction `extended(branch_hint(...))`. When Sema encounters this instruction, it sets `sema.branch_hint` appropriately, and `zirCondBr` etc are expected to reset this value as necessary. The state is on `Sema` rather than `Block` to make it automatically propagate up non-conditional blocks without special handling. If `@panic` is reached, the branch hint is set to `.cold` if none was already set; similarly, error branches get a hint of `.unlikely` if no hint is explicitly provided. If a condition is comptime-known, `cold` hints from the taken branch are allowed to propagate up, but other hints are discarded. This is because a `likely`/`unlikely` hint just indicates the direction this branch is likely to go, which is redundant information when the branch is known at comptime; but `cold` hints indicate that control flow is unlikely to ever reach this branch, meaning if the branch is always taken from its parent, then the parent is also unlikely to ever be reached. This branch information is stored in AIR `cond_br` and `switch_br`. In addition, `try` and `try_ptr` instructions have variants `try_cold` and `try_ptr_cold` which indicate that the error case is cold (rather than just unlikely); this is reachable through e.g. `errdefer unreachable` or `errdefer @panic("")`. A new API `unwrapSwitch` is introduced to `Air` to make it more convenient to access `switch_br` instructions. In time, I plan to update all AIR instructions to be accessed via an `unwrap` method which returns a convenient tagged union a la `InternPool.indexToKey`. The LLVM backend lowers branch hints for conditional branches and switches as follows: * If any branch is marked `unpredictable`, the instruction is marked `!unpredictable`. * Any branch which is marked as `cold` gets a `llvm.assume(i1 true) [ "cold"() ]` call to mark the code path cold. * If any branch is marked `likely` or `unlikely`, branch weight metadata is attached with `!prof`. Likely branches get a weight of 2000, and unlikely branches a weight of 1. In `switch` statements, un-annotated branches get a weight of 1000 as a "middle ground" hint, since there could be likely *and* unlikely *and* un-annotated branches. For functions, a `cold` hint corresponds to the `cold` function attribute, and other hints are currently ignored -- as far as I can tell LLVM doesn't really have a way to lower them. (Ideally, we would want the branch hint given in the function to propagate to call sites.) The compiler and standard library do not yet use this new builtin. Resolves: #21148
2024-08-20Dwarf: emit info about inline call sitesJacob Young
2024-05-22Revert "implement `@expect` builtin (#19658)"Andrew Kelley
This reverts commit a7de02e05216db9a04e438703ddf1b6b12f3fbef. This did not implement the accepted proposal, and I did not sign off on the changes. I would like a chance to review this, please.
2024-05-22implement `@expect` builtin (#19658)David Rubin
* implement `@expect` * add docs * add a second arg for expected bool * fix typo * move `expect` to use BinOp * update to newer langref format
2024-03-06InternPool: create specialized functions for loading namespace typesmlugg
Namespace types (`struct`, `enum`, `union`, `opaque`) do not use structural equality - equivalence is based on their Decl index (and soon will change to AST node + captures). However, we previously stored all other information in the corresponding `InternPool.Key` anyway. For logical consistency, it makes sense to have the key only be the true key (that is, the Decl index) and to load all other data through another function. This introduces those functions, by the name of `loadStructType` etc. It's a big diff, but most of it is no-brainer changes. In future, it might be nice to eliminate a bunch of the loaded state in favour of accessor functions on the `LoadedXyzType` types (like how we have `LoadedUnionType.size()`), but that can be explored at a later date.
2024-03-02Air: replace `.dbg_inline_*` with `.dbg_inline_block`Jacob Young
This prevents the possibility of not emitting a `.dbg_inline_end` instruction and reduces the allocation requirements of the backends. Closes #19093
2024-02-26compiler: decide dbg_var scoping based on AIR blocksmlugg
This commit eliminates the `dbg_block_{begin,end}` instructions from both ZIR and AIR. Instead, lexical scoping of `dbg_var_{ptr,val}` instructions is decided based on the AIR block they exist within. This is a much more robust system, and also results in a huge drop in ZIR bytes - around 7% for Sema.zig. This required some enhancements to Sema to prevent elision of blocks when they are required for debug variable scoping. This can be observed by looking at the AIR for the following simple test program with and without `-fstrip`: ```zig export fn f() void { { var a: u32 = 0; _ = &a; } { var a: u32 = 0; _ = &a; } } ``` When `-fstrip` is passed, no AIR blocks are generated. When `-fno-strip` is passed, the ZIR blocks are lowered to true AIR blocks to give correct lexical scoping to the debug vars. The changes here incidentally reolve #19060. A corresponding behavior test has been added. Resolves: #19060
2024-01-29llvm: ensure returned undef is 0xaa bytes when runtime safety is enabledVeikka Tuominen
Closes #13178
2024-01-23Revert "Don't assume a write if an operand is not in function parameters"Andrew Kelley
This reverts commit 2ab78937dd29fbc299ac434f962a5ff41002cc43. Premature merge - apologies for the disruption. Reopens #15685 Reopens #17580
2024-01-23Don't assume a write if an operand is not in function parametersRahul Prabhu
Liveness assumes that if the operand is not in the parameters of a function call it is being written to, resulting in pointless memcpies.
2024-01-02Liveness: fix branch operands becoming aliasedarbrk1
2023-12-03Air: use typesafe `Air.Inst.Index`Jacob Young
I need some indices for a thing...
2023-09-27Rename `@fabs` to `@abs` and accept integersantlilja
Replaces the @fabs builtin with a new @abs builtins which accepts floats, signed integers and vectors of said types.
2023-06-27Air: store interned values in Air.Inst.Refmlugg
Previously, interned values were represented as AIR instructions using the `interned` tag. Now, the AIR ref directly encodes the InternPool index. The encoding works as follows: * If the ref matches one of the static values, it corresponds to the same InternPool index. * Otherwise, if the MSB is 0, the ref corresponds to an InternPool index. * Otherwise, if the MSB is 1, the ref corresponds to an AIR instruction index (after removing the MSB). Note that since most static InternPool indices are low values (the exceptions being `.none` and `.var_args_param_type`), the first rule is almost a nop.
2023-06-25compiler: start moving safety-checks into backendsAndrew Kelley
This actually used to be how it worked in stage1, and there was this issue to change it: #2649 So this commit is a reversal to that idea. One motivation for that issue was avoiding emitting the panic handler in compilations that do not have any calls to panic. This commit only resolves the panic handler in the event of a safety check function being emitted, so it does not have that flaw. The other reason given in that issue was for optimizations that elide safety checks. It's yet to be determined whether that was a good idea or not; this can get re-explored when we start adding optimization passes to AIR. This commit adds these AIR instructions, which are only emitted if `backendSupportsFeature(.safety_checked_arithmetic)` is true: * add_safe * sub_safe * mul_safe It removes these nonsensical AIR instructions: * addwrap_optimized * subwrap_optimized * mulwrap_optimized The safety-checked arithmetic functions push the burden of invoking the panic handler into the backend. This makes for a messier compiler implementation, but it reduces the amount of AIR instructions emitted by Sema, which reduces time spent in the secondary bottleneck of the compiler. It also generates more compact LLVM IR, reducing time spent in the primary bottleneck of the compiler. Finally, it eliminates 1 stack allocation per safety-check which was being used to store the resulting tuple. These allocations were going to be annoying when combined with suspension points.
2023-06-25liveness: fix merge typo logic errorAndrew Kelley
Oops, I made a terrible mistake when applying a small fixup when merging f10b9e8fd72aae33b127c18e3f8a64a4f56b1b69.
2023-06-24all: migrate code to new cast builtin syntaxmlugg
Most of this migration was performed automatically with `zig fmt`. There were a few exceptions which I had to manually fix: * `@alignCast` and `@addrSpaceCast` cannot be automatically rewritten * `@truncate`'s fixup is incorrect for vectors * Test cases are not formatted, and their error locations change
2023-06-24update Liveness to detect that safety checks do not modify memoryXavier Bouchoux
followup to [25d3713b07a100d8fdb349317db97fd9d0c1e366] Resolves #12215 Previous code didn't account for the extra unreach() that now exists in the air: ``` %29!= block(void, { %30!= cond_br(%22!, { %31!= br(%29, @Air.Inst.Ref.void_value) }, { %2! %15! %27!= call(%26, [%19!, %21]) %28!= unreach() }) } %22!) ```
2023-06-19all: zig fmt and rename "@XToY" to "@YFromX"Eric Joldasov
Signed-off-by: Eric Joldasov <bratishkaerik@getgoogleoff.me>
2023-06-19compiler: rename "@XToY" to "@YFromX", zig fmt: rewrite themEric Joldasov
Signed-off-by: Eric Joldasov <bratishkaerik@getgoogleoff.me>
2023-06-10InternPool: pass by const pointerAndrew Kelley
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
2023-06-10Air: remove constant tagJacob Young
Some uses have been moved to their own tag, the rest use interned. Also, finish porting comptime mutation to be more InternPool aware.
2023-06-10InternPool: remove more legacy valuesJacob Young
Reinstate some tags that will be needed for comptime init.
2023-06-10compiler: move error union types and error set types to InternPoolAndrew Kelley
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.
2023-06-10Sema: update core comptime detection logic to be InternPool awareAndrew Kelley
* Add some assertions to make sure instructions are not none. I tested all these with master branch as well and made sure the behavior tests still passed with the assertions intact (along with a handful of callsite updates). * Fix Sema.resolveMaybeUndefValAllowVariablesMaybeRuntime not noticing that interned values are comptime-known. This was causing all kinds of chaos. * Fix print_air writeType calling tag() without checking for ip_index
2023-06-10stage2: move many Type encodings to InternPoolAndrew Kelley
Notably, `vector`. Additionally, all alternate encodings of `pointer`, `optional`, and `array`.
2023-06-10stage2: add `interned` AIR tagAndrew Kelley
This required additionally passing the `InternPool` into some AIR methods. Also, implement `Type.isNoReturn` for interned types.
2023-06-10stage2: start the InternPool transitionAndrew Kelley
Instead of doing everything at once which is a hopelessly large task, this introduces a piecemeal transition that can be done in small increments at a time. This is a minimal changeset that keeps the compiler compiling. It only uses the InternPool for a small set of types. Behavior tests are not passing. Air.Inst.Ref and Zir.Inst.Ref are separated into different enums but compile-time verified to have the same fields in the same order. The large set of changes is mainly to deal with the fact that most Type and Value methods now require a Module to be passed in, so that the InternPool object can be accessed.
2023-05-12Liveness: simplify logicmlugg
`branch_deaths` was a relic from before I had a full understanding of AIR's control flow structure, and so was unnecessary. This change simplifies Liveness, fixes a bug exposed by #15235, and likely improves performance (due to cloning hashmaps less often).
2023-04-28compiler: use `@memcpy` instead of `std.mem.copy`Andrew Kelley
2023-04-28update codebase to use `@memset` and `@memcpy`Andrew Kelley
2023-04-25stage2: introduce store_safe AIR instructionAndrew Kelley
store: The value to store may be undefined, in which case the destination memory region has undefined bytes after this instruction is evaluated. In such case ignoring this instruction is legal lowering. store_safe: Same as `store`, except if the value to store is undefined, the memory region should be filled with 0xaa bytes, and any other safety metadata such as Valgrind integrations should be notified of this memory region being undefined.
2023-04-25LLVM backend: support non-byte-sized memsetAndrew Kelley
Also introduce memset_safe AIR tag and support it in C backend and LLVM backend.
2023-04-25change semantics of `@memcpy` and `@memset`Andrew Kelley
Now they use slices or array pointers with any element type instead of requiring byte pointers. This is a breaking enhancement to the language. The safety check for overlapping pointers will be implemented in a future commit. closes #14040
2023-04-20Liveness: avoid emitting unused instructions or marking their operands as usedmlugg
Backends want to avoid emitting unused instructions which do not have side effects: to that end, they all have `Liveness.isUnused` checks for many instructions. However, checking this in the backends avoids a lot of potential optimizations. For instance, if a nested field is loaded, then the first field access would still be emitted, since its result is used by the next access (which is then unreferenced). To elide more instructions, Liveness can track this data instead. For operands which do not have to be lowered (i.e. are not side effecting and are not something special like `arg), Liveness can ignore their operand usages, and push the unused information further up, potentially marking many more instructions as unreferenced. In doing this, I also uncovered a bug in the LLVM backend relating to discarding the result of `@cVaArg`, which this change fixes. A behaviour test has been added to cover it.
2023-04-20Liveness: add a liveness verification passJacob Young
This code only runs in a debug zig compiler, similar to verifying llvm modules.
2023-04-20Liveness: control flow analysismlugg
This is a partial rewrite of Liveness, so has some other notable changes: - A proper multi-pass system to prevent code duplication - Better logging - Minor bugfixes
2023-04-07Liveness: defer deaths of externally-scoped instructions in loop bodiesmlugg