This moves some logic from resolveLlvmFunction to updateFunc and takes
advantage of the iteration we already do that takes into account C ABI
lowering, making LLVM parameter attributes accurate for C ABI functions
as well as our own unspecified calling convention.
Related to #11498.
Generally, the load instruction may need to make a copy of an
isByRef=true value, such as in the case of the following code:
```zig
pub fn swap(comptime T: type, a: *T, b: *T) void {
const tmp = a.*;
a.* = b.*;
b.* = tmp;
}
```
However, it only needs to do so if there are any instructions which can
possibly write to memory. When calling functions with isByRef=true
parameters, the AIR code that is generated looks like loads followed
directly by call.
This allows for a peephole optimization when lowering loads: if the load
instruction operates on an isByRef=true type and dies before any side effects
occur, then we can safely lower the load as a no-op that returns its
operand.
This is one out of three changes I intend to make to address #11498.
However I will put these changes in separate branches and merge them
separately so that we can have three independent points on the perf
charts.
This is one out of three changes I intend to make to address #11498.
However I will put these changes in separate branches and merge them
separately so that we can have three independent points on the perf
charts.
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
* `?E` where E is an error set with only one field now lowers the same
as `bool`.
* Fix implementation of errUnionErrOffset and errUnionPayloadOffset to
properly compute the offset of each field. Also name them the same
as the corresponding LLVM functions and have the same function
signature, to avoid confusion. This fixes a bug where wasm was
passing the error union type instead of the payload type.
* Fix C backend handling of optionals with zero-bit payload types.
* C backend: separate out airOptionalPayload and airOptionalPayloadPtr
which reduces branching and cleans up control flow.
* Make Type.isNoReturn return true for error sets with no fields.
* Make `?error{}` have only one possible value (null).
* Sema: avoid unnecessary safety checks when an error set is empty.
* Sema: make zirErrorToInt handle comptime errors that are represented
as integers.
* Sema: make empty error sets properly integrate with
typeHasOnePossibleValue.
* Type: correct the ABI alignment and size of error unions which have
both zero-bit error set and zero-bit payload. The previous code did
not account for the fact that we still need to store a bit for
whether there is an error.
* LLVM: lower error unions possibly with the payload first or with the
error code first, depending on alignment. Previously it always put
the error code first and used a padding array.
* LLVM: lower functions which have an empty error set as the return
type the same as anyerror, so that they can be used where
fn()anyerror function pointers are expected. In such functions, Zig
will lower ret to returning zero instead of void.
As a result, one more behavior test is passing.
This is a temporary addition to stage2 in order to match stage1 behavior,
however the end-game once the lang spec is settled will be to use a global
InternPool for comptime memoized objects, making this behavior consistent
across all types, not only string literals. Or, we might decide to not
guarantee string literals to have equal comptime pointers, in which case
this commit can be reverted.
The previous commit caused LLVM module verification failure because we
attemped to bitcast LLVM pointers to i64 parameters. This is exactly
what we want, however it's technically not allowed according to LLVM's
type system. It could have been fixed trivially by using ptrtoint
instead of bitcast in the case of pointers, however, out of concern for
inttoptr being problematic for the optimizer, I put in special code to
detect when a given parameter can be treated as its actual type rather
than an integer type. This makes Zig's output LLVM IR closer to what
Clang outputs.
The previous implementation of calling conventions was hacky and broken.
This commit reworks lowerFnParamTy into iterateParamTypes which returns
enum tags indicating how to handle each parameter. This is then used in
the three places that matter:
* lowering a function type to llvm type
* converting function parameters to the canonical type representation
(with respect to isByRef).
* converting canonical type representation to function arguments at
callsites (again with respect to isByRef).
As a result, we are one step closer to the C ABI tests passing. Before
this commit, attempting to build them crashed the compiler. I isolated
the broken function and verified that it now is lowered correctly. I
will keep working on this one piece at a time until all the C ABI tests
pass, and then I will enable all of them in the CI.
Most of the work here was additions to zig.h. The lowering code is
mainly responsible for calling the correct function name depending on
the operand type.
Some of the compiler-rt calls here are not implemented yet and are
non-standard symbols due to the C programming language not needing them.
After this commit, the behavior tests with -ofmt=c are passing again.
Rename all references of sparcv9 to sparc64, to make Zig align more with
other projects. Also, added new function to convert glibc arch name to Zig
arch name, since it refers to the architecture as sparcv9.
This is based on the suggestion by @kubkon in PR 11847.
(https://github.com/ziglang/zig/pull/11487#pullrequestreview-963761757)
If the hw doesn't have support for exotic floating-point types such
as `f80`, we lower the call to a compiler-rt function call instead.
I've added a behavior test specifically targeting this use case which
now passes on `aarch64-macos`.
Additionally, this commit makes it possible to successfully build
stage3 on `aarch64-macos`. We can print the compiler's help message,
however, building with it needs a little bit more love still.
* sret logic needed a check for hasRuntimeBits()
* lower f128 on windows targets with the "sse" class rather than
"memory". For reference, clang emits a compile error when __float128
is used with the MSVC ABI, saying that this type is not supported.
The docs for the x64 calling convention have both of these sentences:
- "Any argument that doesn't fit in 8 bytes, or isn't 1, 2, 4, or 8 bytes,
must be passed by reference."
- "All floating point operations are done using the 16 XMM registers."
* For i128, however, it is clear that the Windows calling convention
wants such an object to be passed by reference. I fixed the LLVM
lowering for function parameters to make this work.
So far it's supported by the LLVM backend only. I recommend for the
other backends to wait for the resolution of #10761 before adding
support for this feature.
Prior to this commit, the logic for ABI size and ABI alignment for
integers was naive and incorrect. This results in wasted hardware as
well as undefined behavior in the LLVM backend when we memset an
incorrect number of bytes to 0xaa due to disagreeing with LLVM about the
ABI size of integers.
This commit introduces a "max int align" value which is different per
Target. This value is used to derive the ABI size and alignment of all
integers.
This commit makes an interesting change from stage1, which treats
128-bit integers as 16-bytes aligned for x86_64-linux. stage1 is
incorrect. The maximum integer alignment on this system is only 8 bytes.
This change breaks the behavior test called "128-bit cmpxchg" because on
that target, 128-bit cmpxchg does require a 16-bytes aligned pointer to
a 128 bit integer. However, this alignment property does not belong on
*all* 128 bit integers - only on the pointer type in the `@cmpxchg`
builtin function prototype. The user can then use an alignment override
annotation on a 128-bit integer variable or struct field to obtain such
a pointer.
* 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
Just like for Struct in 8238d4b33585a715c58ab559cd001dd3ea1db55b, in the
case of ErrorUnion struct we need to return a compound literal "(T){...}"
instead of just "{}", which is invalid code when used in e.g. a "return"
expression.
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.
* std.math.snan: fix compilation error. Also make it and nan inline.
* LLVM: use a proper enum type for float op instead of enum literal.
Also various cleanups.
* LLVM: use LLVMBuildVectorSplat for vector splat AIR instruction.
- also the bindings had parameter order wrong
* LLVM: additionally handle f16 lowering. For now all targets report OK
but I think we will need to add some exceptions to this list.
Updates stage2 to manually lower softfloat operations for all unary
floating point operations and arithmetic.
Softfloat support still needs to be added for conversion operators
(float<->float and int<->float)
For parameters and return types of functions with the C calling
convention, the LLVM backend now has a special lowering for the function
type that makes the function adhere to the C ABI. The AIR instruction
lowerings for call, ret, and ret_load are adjusted to bitcast the real
type to the ABI type if necessary.
More work on this will need to be done, however, this improvement is
enough that stage3 now passes all the same behavior tests that stage2
passes - notably, translate-c no longer has a segfault due to C ABI
issues with Zig's Clang C API wrapper.
Rather than allocating Decl objects with an Allocator, we instead allocate
them with a SegmentedList. This provides four advantages:
* Stable memory so that one thread can access a Decl object while another
thread allocates additional Decl objects from this list.
* It allows us to use u32 indexes to reference Decl objects rather than
pointers, saving memory in Type, Value, and dependency sets.
* Using integers to reference Decl objects rather than pointers makes
serialization trivial.
* It provides a unique integer to be used for anonymous symbol names,
avoiding multi-threaded contention on an atomic counter.