* Introduce "_ptr" variants of ZIR try instruction to disallow constructs
such as `try` on a pointer value instead of an error union value.
* Disable the "_inline" variants of the ZIR try instruction for now because
we are out of ZIR tags. I will free up some space in an independent commit.
* AstGen: fix tryExpr calling rvalue() on ResultLoc.ref
Implements semantic analysis for the new try/try_inline ZIR
instruction. Adds the new try/try_ptr AIR instructions and implements
them for the LLVM backend.
Fixes not calling rvalue() for tryExpr in AstGen.
This is part of an effort to implement #11772.
Additionally:
* Sema: fix array cat/mul not setting the sentinel value
- This required an LLVM backend enhancement to the handling of the
AIR instruction aggregate_init that likely needs to be
propagated to the other backends.
* Sema: report integer overflow of array concatenation in a proper
compile error instead of crashing.
* Sema: fix not using proper pointer address space for array cat/mul
* outputs can have names and be referenced with template replacements
the same as inputs.
* fix print_air.zig not decoding correctly.
* LLVM backend: use a table for template names for simplicity
The reason for having `@tan` is that we already have `@sin` and `@cos`
because some targets have machine code instructions for them, but in the
case that the implementation needs to go into compiler-rt, sin, cos, and
tan all share a common dependency which includes a table of data. To
avoid duplicating this table of data, we promote tan to become a builtin
alongside sin and cos.
ZIR: The tag enum is at capacity so this commit moves
`field_call_bind_named` to be `extended`. I measured this as one of
the least used tags in the zig codebase.
Fix libc math suffix for `f32` being wrong in both stage1 and stage2.
stage1: add missing libc prefix for float functions.
This commit introduces a new AIR instruction `cmp_lt_errors_len`. It's
specific to this use case for two reasons:
* The total number of errors is not stable during semantic analysis; it
can only be reliably checked when flush() is called. So the backend
that is lowering the instruction must emit a relocation of some kind
and then populate it during flush().
* The fewer AIR instructions in memory, the better for compiler
performance, so we squish complex meanings into AIR tags without
hesitation.
The instruction is implemented only in the LLVM backend so far. It does
this by creating a simple function which is gutted and re-populated
with each flush().
AstGen now uses ResultLoc.coerced_ty for `@intToError` and Sema does the
coercion.
add_with_overflow and similar functions now have the ty_pl data
attached. The Payload will now be a binary operation and the inst is
expected to return a tuple consisting of the destination integer type
and an overflow bit (u1).
Co-authored-by: Jan Philipp Hafer <jan.hafer@rwth-aachen.de>
That happens after a function body is analyzed. This prevents circular
dependency compile errors and yet a way to mark types that need to be
fully resolved before a given function is sent to the codegen backend.
The existing `cmp_*` instructions get their result type from `lhs`, but
vector comparison will always return a vector of bools with only the
length derived from its operands. This necessitates the creation of a
new AIR instruction.
Notably, Value.eql and Value.hash are improved to treat NaN as equal to
itself, so that Type/Value can be hash map keys. Likewise float hashing
normalizes the float value before computing the hash.
Adds 2 new AIR instructions:
* dbg_var_ptr
* dbg_var_val
Sema no longer emits dbg_stmt AIR instructions when strip=true.
LLVM backend: fixed lowerPtrToVoid when calling ptrAlignment on
the element type is problematic.
LLVM backend: fixed alloca instructions improperly getting debug
location annotated, causing chaotic debug info behavior.
zig_llvm.cpp: fixed incorrect bindings for a function that should use
unsigned integers for line and column.
A bunch of C test cases regressed because the new dbg_var AIR
instructions caused their operands to be alive, exposing latent bugs.
Mostly it's just a problem that the C backend lowers mutable
and const slices to the same C type, so we need to represent that in the
C backend instead of printing two duplicate typedefs.
* use the real start code for LLVM backend with x86_64-linux
- there is still a check for zig_backend after initializing the TLS
area to skip some stuff.
* introduce new AIR instructions and implement them for the LLVM
backend. They are the same as `call` except with a modifier.
- call_always_tail
- call_never_tail
- call_never_inline
* LLVM backend calls hasRuntimeBitsIgnoringComptime in more places to
avoid unnecessarily depending on comptimeOnly being resolved for some
types.
* LLVM backend: remove duplicate code for setting linkage and value
name. The canonical place for this is in `updateDeclExports`.
* LLVM backend: do some assembly template massaging to make `%%`
rendered as `%`. More hacks will be needed to make inline assembly
catch up with stage1.
* mul_add AIR instruction: use `pl_op` instead of `ty_pl`. The type is
always the same as the operand; no need to waste bytes redundantly
storing the type.
* AstGen: use coerced_ty for all the operands except for one which we
use to communicate the type.
* Sema: use the correct source location for requireRuntimeBlock in
handling of `@mulAdd`.
* native backends: handle liveness even for the functions that are
TODO.
* C backend: implement `@mulAdd`. It lowers to libc calls.
* LLVM backend: make `@mulAdd` handle all float types.
- improved fptrunc and fpext to handle f80 with compiler-rt calls.
* Value.mulAdd: handle all float types and use the `@mulAdd` builtin.
* behavior tests: revert the changes to testing `@mulAdd`. These
changes broke the test coverage, making it only tested at
compile-time.
Improved f80 support:
* std.math.fma handles f80
* move fma functions from freestanding libc to compiler-rt
- add __fmax and fmal
- make __fmax and fmaq only exported when they don't alias fmal.
- make their linkage weak just like the rest of compiler-rt symbols.
* removed `longDoubleIsF128` and replaced it with `longDoubleIs` which
takes a type as a parameter. The implementation is now more accurate
and handles more targets. Similarly, in stage2 the function
CTypes.sizeInBits is more accurate for long double for more targets.
* AIR: use pl_op instead of ty_pl for wasm_memory_size. No need to
store the type because the type is always `u32`.
* AstGen: use coerced_ty for `@wasmMemorySize` and `@wasmMemoryGrow`
and do the coercions in Sema.
* Sema: use more accurate source locations for errors.
* Provide more information in the compiler error message.
* Codegen: use liveness data to avoid lowering unused
`@wasmMemorySize`.
* LLVM backend: add implementation
- I wasn't able to test it because we are hitting a linker error for
`-target wasm32-wasi -fLLVM`.
* C backend: use `zig_unimplemented()` instead of silently doing wrong
behavior for these builtins.
* behavior tests: branch only on stage2_arch for inclusion of the
wasm.zig file. We would change it to `builtin.cpu.arch` but that is
causing a compiler crash on some backends.
This implements the wasm builtins by lowering to builtins that are supported by c-compilers.
In this case: Clang.
This also simplifies the `AIR` instruction as it now uses the payload field of `ty_pl` and `pl_op`
directly to store the index argument rather than storing it inside Extra. This saves us 4 bytes
per builtin call.
Similarly to the other wasm builtin, this implements the grow variation where the memory
index is a comptime known value. The operand as well as the result are runtime values.
This also verifies during semantic analysis the target we're building for is wasm, or else
emits a compilation error. This means that other backends do not have to handle this AIR instruction,
other than the wasm and LLVM backends.
This implements the `wasmMemorySize` builtin, in Sema and the Wasm backend.
The Stage2 implementation differs from stage1 in the way that `index` must be a comptime value.
The stage1 variant is incorrect, as the index is part of the instruction encoding, and therefore,
cannot be a runtime value.
The ZIR instruction `union_init_ptr` is renamed to `union_init`.
I made it always use by-value semantics for now, not taking the time to
invest in result location semantics, in case we decide to change the
rules for unions. This way is much simpler.
There is a new AIR instruction: union_init. This is for a comptime known
tag, runtime-known field value.
vector_init is renamed to aggregate_init, which solves a TODO comment.
Prior to this commit, the AIR arg instruction kept a reference to a ZIR
string index for the corresponding parameter name. This is used by DWARF
emitting code. However, this is a design flaw because we want AIR
objects to be independent from ZIR.
This commit saves the parameter names into memory managed by
`Module.Fn`. This is sub-optimal because we should be able to get the
parameter names from the ZIR for a function without having them
redundantly stored along with `Fn` memory. However the current way that
ZIR param instructions are encoded does not support this case. They
appear in the same ZIR body as the function instruction, just before it.
Instead, they should be embedded within the function instruction, which
will allow this TODO to be solved. That improvement is too big for this
commit, however.
After this there is one last dependency to untangle, which is for inline
assembly. The issue for that is #10784.
When Sema sees a store_node instruction, it now checks for
the possibility of this pattern:
%a = ret_ptr
%b = store(%a, %c)
Where %c is an error union. In such case we need to add to the
current function's inferred error set, if any.
Coercion from error union to error union will be handled ideally if the
operand is comptime known. In such case it does the appropriate
unwrapping, then wraps again.
In the future, coercion from error union to error union should do the
same thing for a runtime value; emitting a runtime branch to check if
the value is an error or not.
`Value.arrayLen` for structs returns the number of fields. This is so
that Liveness can use it for the `vector_init` instruction (soon to be
renamed to `aggregate_init`).
Support for f128, comptime_float, and c_longdouble require improvements
to compiler_rt and will implemented in a later PR. Some of the code in
this commit could be made more generic, for instance `llvm.airSqrt`
could probably be `llvm.airUnaryMath`, but let's cross that
bridge when we get to it.
* AIR instruction vector_init gains the ability to init arrays and
tuples in addition to vectors. This will probably also gain the
ability to initialize structs and be renamed to `aggregate_init`.
* AstGen prefers to use an `anon_array_init` ZIR instruction for
local variables when the init expr is an array literal and there is
no type.
This reverts commit d48e4245b68bf25c7f41804a5012ac157a5ee546.
I have no idea why this is failing Drone CI, but in a branch, reverting
this commit solved the problem.
AIR:
* `array_elem_val` is now allowed to be used with a vector as the array
type.
* New instructions: splat, vector_init
AstGen:
* The splat ZIR instruction uses coerced_ty for the ResultLoc, avoiding
an unnecessary `as` instruction, since the coercion will be performed
in Sema.
* Builtins that accept vectors now ignore the type parameter. Comment
from this commit reproduced here:
The accepted proposal #6835 tells us to remove the type parameter from
these builtins. To stay source-compatible with stage1, we still observe
the parameter here, but we do not encode it into the ZIR. To implement
this proposal in stage2, only AstGen code will need to be changed.
Sema:
* `clz` and `ctz` ZIR instructions are now handled by the same function
which accept AIR tag and comptime eval function pointer to
differentiate.
* `@typeInfo` for vectors is implemented.
* `@splat` is implemented. It takes advantage of `Value.Tag.repeated` 😎
* `elemValue` is implemented for vectors, when the index is a scalar.
Handling a vector index is still TODO.
* Element-wise coercion is implemented for vectors. It could probably
be optimized a bit, but it is at least complete & correct.
* `Type.intInfo` supports vectors, returning int info for the element.
* `Value.ctz` initial implementation. Needs work.
* `Value.eql` is implemented for arrays and vectors.
LLVM backend:
* Implement vector support when lowering `array_elem_val`.
* Implement vector support when lowering `ctz` and `clz`.
* Implement `splat` and `vector_init`.
Introduced a new AIR instruction: `tag_name`. Reasons to do this
instead of lowering it in Sema to a switch, function call, array
lookup, or if-else tower:
* Sema is a bottleneck; do less work in Sema whenever possible.
* If any optimization passes run, and the operand to becomes
comptime-known, then it could change to have a comptime result
value instead of lowering to a function or array or something which
would then have to be garbage-collected.
* Backends may want to choose to use a function and a switch branch,
or they may want to use a different strategy.
Codegen for `@tagName` is implemented for the LLVM backend but not any
others yet.
Introduced some new `Type` tags:
* `const_slice_u8_sentinel_0`
* `manyptr_const_u8_sentinel_0`
The motivation for this was to make typeof() on the tag_name AIR
instruction non-allocating.
A bunch more enum tests are passing now.