51 Commits

Author SHA1 Message Date
mlugg
457c94d353
compiler: implement @branchHint, replacing @setCold
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-27 00:41:49 +01:00
David Rubin
f777b29832
fix up merge conflicts with master 2024-08-25 22:43:57 -07:00
David Rubin
1c1feba08e
remove mod aliases for Zcus 2024-08-25 15:17:40 -07:00
David Rubin
80cd53d3bb
sema: clean-up {union,struct}FieldAlignment and friends
My main gripes with this design were that it was incorrectly namespaced, the naming was inconsistent and a bit wrong (`fooAlign` vs `fooAlignment`).

This commit moves all the logic from `PerThread.zig` to use the zcu + tid system that the previous couple commits introduce.
I've organized and merged the functions to be a bit more specific to their own purpose.

- `fieldAlignment` takes a struct or union type, an index, and a Zcu (or the Sema version which takes a Pt), and gives you the alignment of the field at the index.
- `structFieldAlignment` takes the field type itself, and provides the logic to handle special cases, such as externs.

A design goal I had in mind was to avoid using the word 'struct' in the function name, when it worked for things that aren't structs, such as unions.
2024-08-25 15:16:46 -07:00
David Rubin
b4bb64ce78
sema: rework type resolution to use Zcu when possible 2024-08-25 15:16:42 -07:00
mlugg
7d54c62c8a incremental: fix adding/removing aggregate fields
I don't recall why I put these checks here -- they aren't correct. We
can freely recreate a type even if its fields have changed, because we
are going to re-do all type resolution.

The only conditions for recreations are (a) the ZIR index must not be
lost and (b) the number of captures must be the same. These conditions
are permissible because if either is violated, we can guarantee that
analysis of a valid `zirStructDecl` (etc) will never reference this
type (since the ZIR index has just been tracked, and the captures have
just been created based on the ZIR).

Adds a corresponding test case.

Resolves: #21185
2024-08-24 20:30:52 +01:00
Jacob Young
eaa227449c Dwarf: fix issues with inline call sites 2024-08-20 15:08:23 -04:00
Jacob Young
62f7276501 Dwarf: emit info about inline call sites 2024-08-20 08:09:33 -04:00
mlugg
de49a9a173
Zir: add instructions to fetch std.builtin types
This replaces the constant `Zir.Inst.Ref` tags (and the analagous tags
in `Air.Inst.Ref`, `InternPool.Index`) referring to types in
`std.builtin` with a ZIR instruction `extended(builtin_type(...))` which
instructs Sema to fetch such a type, effectively as if it were a
shorthand for the ZIR for `@import("std").builtin.xyz`.

Previously, this was achieved through constant tags in `Ref`. The
analagous `InternPool` indices began as `simple_type` values, and were
later rewritten to the correct type information. This system was kind of
brittle, and more importantly, isn't compatible with incremental
compilation of std, since incremental compilation relies on the ability
to recreate types at different indices when they change. Replacing the
old system with this instruction slightly increases the size of ZIR, but
it simplifies logic and allows incremental compilation to work correctly
on the standard library.

This shouldn't have a significant impact on ZIR size or compiler
performance, but I will take measurements in the PR to confirm this.
2024-08-18 18:10:59 +01:00
mlugg
b745fee1f8
frontend: handle incremental updates of replaced runtime functions 2024-08-18 18:10:59 +01:00
mlugg
93a5bd262d
frontend: removed resolved IES data for outdated functions
Without this, incremental updates which would change inferred error sets
fail, since they assume the IES is resolved and equals the old set,
resulting in false positive compile errors when e.g. coercing to an IES.
2024-08-18 18:10:59 +01:00
mlugg
9e6318a4ea compiler: add some doc comments 2024-08-17 18:50:10 -04:00
mlugg
84c2ebd6c6 frontend: incremental compilation progress
Another big commit, sorry! This commit makes all fixes necessary for
incremental updates of the compiler itself (specifically, adding a
breakpoint to `zirCompileLog`) to succeed, at least on the frontend.

The biggest change here is a reform to how types are handled. It works
like this:
* When a type is first created in `zirStructDecl` etc, its namespace is
  scanned. If the type requires resolution, an `interned` dependency is
  declared for the containing `AnalUnit`.
* `zirThis` also declared an `interned` dependency for its `AnalUnit` on
  the namespace's owner type.
* If the type's namespace changes, the surrounding source declaration
  changes hash, so `zirStructDecl` etc will be hit again. We check
  whether the namespace has been scanned this generation, and re-scan it
  if not.
* Namespace lookups also check whether the namespace in question
  requires a re-scan based on the generation. This is because there's no
  guarantee that the `zirStructDecl` is re-analyzed before the namespace
  lookup is re-analyzed.
* If a type's structure (essentially its fields) change, then the type's
  `Cau` is considered outdated. When the type is re-analyzed due to
  being outdated, or the `zirStructDecl` is re-analyzed by being
  transitively outdated, or a corresponding `zirThis` is re-analyzed by
  being transitively outdated, the struct type is recreated at a new
  `InternPool` index. The namespace's owner is updated (but not
  re-scanned, since that is handled by the mechanisms above), and the
  old type, while remaining a valid `Index`, is removed from the map
  metadata so it will never be found by lookups. `zirStructDecl` and
  `zirThis` store an `interned` dependency on the *new* type.
2024-08-17 18:50:10 -04:00
mlugg
46388d338a InternPool: don't remove outdated types
When a type becomes outdated, there will still be lingering references
to the old index -- for instance, any declaration whose value was that
type holds a reference to that index. These references may live for an
arbitrarily long time in some cases. So, we can't just remove the type
from the pool -- the old `Index` must remain valid!

Instead, we want to preserve the old `Index`, but avoid it from ever
appearing in lookups. (It's okay if analysis of something referencing
the old `Index` does weird stuff -- such analysis are guaranteed by the
incremental compilation model to always be unreferenced.) So, we use the
new `InternPool.putKeyReplace` to replace the shard entry for this index
with the newly-created index.
2024-08-17 18:50:10 -04:00
mlugg
8f8fe89276 Zcu: panic on usingnamespace with -fincremental 2024-08-17 18:50:10 -04:00
mlugg
93f2d9a77f Zcu: typo
We were accidentally over-reporting most `namespace_name` deps and *not*
reporting some actually outdated ones!
2024-08-17 18:50:10 -04:00
mlugg
aa6c1c40ec frontend: yet more incremental work 2024-08-17 18:50:10 -04:00
mlugg
895267c916 frontend: incremental progress
This commit makes more progress towards incremental compilation, fixing
some crashes in the frontend. Notably, it fixes the regressions introduced
by #20964. It also cleans up the "outdated file root" mechanism, by
virtue of deleting it: we now detect outdated file roots just after
updating ZIR refs, and re-scan their namespaces.
2024-08-17 18:50:10 -04:00
Jacob Young
ef11bc9899 Dwarf: rework self-hosted debug info from scratch
This is in preparation for incremental and actually being able to debug
executables built by the x86_64 backend.
2024-08-16 15:22:55 -04:00
mlugg
153e7d6235
frontend: give all container types namespaces
Eliding the namespace when a container type has no decls was an
experiment in saving memory, but it ended up causing more trouble than
it was worth in various places. So, take the small memory hit for
reified types, and just give every container type a namespace.
2024-08-11 07:30:21 +01:00
mlugg
548a087faf
compiler: split Decl into Nav and Cau
The type `Zcu.Decl` in the compiler is problematic: over time it has
gained many responsibilities. Every source declaration, container type,
generic instantiation, and `@extern` has a `Decl`. The functions of
these `Decl`s are in some cases entirely disjoint.

After careful analysis, I determined that the two main responsibilities
of `Decl` are as follows:
* A `Decl` acts as the "subject" of semantic analysis at comptime. A
  single unit of analysis is either a runtime function body, or a
  `Decl`. It registers incremental dependencies, tracks analysis errors,
  etc.
* A `Decl` acts as a "global variable": a pointer to it is consistent,
  and it may be lowered to a specific symbol by the codegen backend.

This commit eliminates `Decl` and introduces new types to model these
responsibilities: `Cau` (Comptime Analysis Unit) and `Nav` (Named
Addressable Value).

Every source declaration, and every container type requiring resolution
(so *not* including `opaque`), has a `Cau`. For a source declaration,
this `Cau` performs the resolution of its value. (When #131 is
implemented, it is unsolved whether type and value resolution will share
a `Cau` or have two distinct `Cau`s.) For a type, this `Cau` is the
context in which type resolution occurs.

Every non-`comptime` source declaration, every generic instantiation,
and every distinct `extern` has a `Nav`. These are sent to codegen/link:
the backends by definition do not care about `Cau`s.

This commit has some minor technically-breaking changes surrounding
`usingnamespace`. I don't think they'll impact anyone, since the changes
are fixes around semantics which were previously inconsistent (the
behavior changed depending on hashmap iteration order!).

Aside from that, this changeset has no significant user-facing changes.
Instead, it is an internal refactor which makes it easier to correctly
model the responsibilities of different objects, particularly regarding
incremental compilation. The performance impact should be negligible,
but I will take measurements before merging this work into `master`.

Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2024-08-11 07:29:41 +01:00
Jacob Young
4f742c4cfc dev: introduce dev environments that enable compiler feature sets 2024-07-19 22:35:33 -07:00
Matthew Lugg
e82f7d3800
Merge pull request #20653 from mlugg/incremental-fix
Zcu: updateZirRefs typo
2024-07-17 00:08:13 +01:00
Jacob Young
88bb0fd288
Merge pull request #20632 from jacobly0/codegen-thread
InternPool: enable separate codegen/linking thread
2024-07-16 14:49:49 -04:00
mlugg
21cde7ad90
Zcu: updateZirRefs typo 2024-07-16 19:46:10 +01:00
Matthew Lugg
ee695c8ef4
Merge pull request #20637 from mlugg/comptime-resolution-strat
Type,Value: mark `ResolveStrat` parameter of type queries as `comptime`
2024-07-16 19:22:39 +01:00
mlugg
b1d3d48f68
Type,Value: mark ResolveStrat parameter of type queries as comptime
This eliminates the statically-reachable recursion loop between code
generation backends and Sema. This is beneficial for optimizers
(although I do not measure any performance improvement for this change),
and for profilers.
2024-07-16 11:38:20 +01:00
Jacob Young
9d1820d206 InternPool: reduce max tid width by one bit
@mlugg keeps stealing my bits!
2024-07-16 06:28:41 -04:00
Andrew Kelley
60318a1e39 frontend: move updateZirRefs to be single-threaded
for simplicity's sake. This makes it O(M) instead of O(N*M) where N is
tracked insts and M is number of changed source files.
2024-07-15 18:54:41 -07:00
Andrew Kelley
716b128a24 frontend: add -fincremental, -fno-incremental flag
Remove --debug-incremental

This flag is also added to the build system. Importantly, this tells
Compile step whether or not to keep the compiler running between
rebuilds. It defaults off because it is currently crashing
zirUpdateRefs.
2024-07-14 21:18:09 -07:00
Andrew Kelley
abf8955951 make zig compiler processes live across rebuilds
Changes the `make` function signature to take an options struct, which
additionally includes `watch: bool`. I intentionally am not exposing
this information to configure phase logic.

Also adds global zig cache to the compiler cache prefixes.

Closes #20600
2024-07-14 19:51:16 -07:00
Jacob Young
2ff49751aa Compilation: introduce work stages for better work distribution 2024-07-13 04:47:38 -04:00
Jacob Young
a1053e8e1d InternPool: add and use a mutate mutex for each list
This allows the mutate mutex to only be locked during actual grows,
which are rare. For the lists that didn't previously have a mutex, this
change has little effect since grows are rare and there is zero
contention on a mutex that is only ever locked by one thread.  This
change allows `extra` to be mutated without racing with a grow.
2024-07-13 04:47:38 -04:00
Andrew Kelley
5a34e6c3e6 frontend: add file system inputs for incremental cache mode
These are also used for whole cache mode in the case that any compile
errors are emitted.
2024-07-12 00:15:11 -07:00
Jacob Young
c2316c5228 InternPool: make global_error_set thread-safe 2024-07-10 21:39:55 -04:00
Jacob Young
afa66fa392 InternPool: make tracked_insts thread-safe 2024-07-10 14:42:50 -04:00
Jacob Young
f290b54f89 InternPool: make files more thread-safe 2024-07-10 11:20:08 -04:00
Jacob Young
8f292431b0 InternPool: fix undefined decl fully qualified name
This is now possible after moving `File.Index` to `*File` mapping into
intern pool.
2024-07-10 11:20:08 -04:00
Jacob Young
3d2dfbe828 InternPool: add FileIndex to *File mapping 2024-07-10 11:20:08 -04:00
mlugg
f93a10f664 Air: store param names directly instead of referencing Zir 2024-07-10 11:20:08 -04:00
Jacob Young
667b4f9054 Zcu: cache fully qualified name on Decl
This avoids needing to mutate the intern pool from backends.
2024-07-10 11:10:49 -04:00
Andrew Kelley
b3b923e51f
Merge pull request #20561 from jacobly0/debug-segfaults
debug: prevent segfaults on linux
2024-07-09 21:03:36 -04:00
Jacob Young
c5283eb49b InternPool: implement thread-safe allocated lists 2024-07-09 17:29:01 -04:00
mlugg
47846bc17c Zcu: fix passing exported decls with compile errors to the backend 2024-07-09 12:53:19 -04:00
Jacob Young
65ced4a334 Compilation: put supported codegen backends on a separate thread
(There are no supported backends.)
2024-07-08 11:00:38 -04:00
Jacob Young
bdae01ab04 InternPool: implement and use thread-safe list for extra and limbs 2024-07-07 22:59:52 -04:00
Jacob Young
383cffbfae InternPool: temporarily disable multi-threaded behavior
This reduces the cost of the new data structure until the multi-threaded
behavior is actually used.
2024-07-07 22:59:52 -04:00
Jacob Young
92ddb959a7 InternPool: implement and use thread-safe list for items 2024-07-07 22:59:52 -04:00
Jacob Young
8293ff94cf InternPool: implement and use thread-safe list for strings 2024-07-07 22:59:52 -04:00
Jacob Young
ca02266157 Zcu: pass PerThread to intern pool string functions 2024-07-07 22:59:52 -04:00