* AstGen: fix not emitting `struct_init_empty` when an explicit type is
present in struct initialization syntax.
* AstGen: these two syntaxes now lower to identical ZIR:
- `var a = A{ .b = c };`
- `var a = @as(A, .{ .b = c });`
* Zir: clarify `auto_enum_tag` in the doc comments.
* LLVM Backend: fix lowering of function return types when the type has
0 bits.
* prepare compiler-rt to support being compiled by stage2
- put in a few minor workarounds that will be removed later, such as
using `builtin.stage2_arch` rather than `builtin.cpu.arch`.
- only try to export a few symbols for now - we'll move more symbols
over to the "working in stage2" section as they become functional
and gain test coverage.
- use `inline fn` at function declarations rather than `@call` with an
always_inline modifier at the callsites, to avoid depending on the
anonymous array literal syntax language feature (for now).
* AIR: replace floatcast instruction with fptrunc and fpext for
shortening and widening floating point values, respectively.
* Introduce a new ZIR instruction, `export_value`, which implements
`@export` for the case when the thing to be exported is a local
comptime value that points to a function.
- AstGen: fix `@export` not properly reporting ambiguous decl
references.
* Sema: handle ExportOptions linkage. The value is now available to all
backends.
- Implement setting global linkage as appropriate in the LLVM
backend. I did not yet inspect the LLVM IR, so this still needs to
be audited. There is already a pending task to make sure the alias
stuff is working as intended, and this is related.
- Sema almost handles section, just a tiny bit more code is needed in
`resolveExportOptions`.
* Sema: implement float widening and shortening for both `@floatCast`
and float coercion.
- Implement the LLVM backend code for this as well.
There were two things to resolve here:
* Snektron's branch edited Zir printing, but in master branch
I moved the printing code from Zir.zig to print_zir.zig. So that
just had to be moved over.
* In master branch I fleshed out coerceInMemory a bit more, which
caused one of Snektron's test cases to fail, so I had to add
addrspace awareness to that. Once I did that the tests passed again.
* introduce float_to_int and int_to_float AIR instructionts and
implement for the LLVM backend and C backend.
* Sema: implement `zirIntToFloat`.
* Sema: implement `@atomicRmw` comptime evaluation
- introduce `storePtrVal` for when one needs to store a Value to a
pointer which is a Value, and assert it happens at comptime.
* Value: introduce new functionality:
- intToFloat
- numberAddWrap
- numberSubWrap
- numberMax
- numberMin
- bitwiseAnd
- bitwiseNand (not implemented yet)
- bitwiseOr
- bitwiseXor
* Sema: hook up `zirBitwise` to the new Value bitwise implementations
* Type: rename `isFloat` to `isRuntimeFloat` because it returns `false`
for `comptime_float`.
This is a property which solely belongs to pointers to functions,
not to the functions themselves. This cannot be properly represented by
stage 2 at the moment, as type with zigTypeTag() == .Fn is overloaded for
for function pointers and function prototypes.
* test runner is improved to respect `error.SkipZigTest`
* start code is improved to `@setAlignStack(16)` before calling main()
* the newly passing behavior test has a workaround for the fact that
stage2 cannot yet call `std.Target.x86.featureSetHas()` at comptime.
This is blocking on comptime closures. The workaround is that there
is a new decl `@import("builtin").stage2_x86_cx16` which is a `bool`.
* Implement `@setAlignStack`. This language feature should be re-evaluated
at some point - I'll file an issue for it.
* LLVM backend: apply/remove the cold attribute and noinline attribute
where appropriate.
* LLVM backend: loads and stores are properly annotated with alignment
and volatile attributes.
* LLVM backend: allocas are properly annotated with alignment.
* Type: fix integers reporting wrong alignment for 256-bit integers and
beyond. Once you get to 16 byte aligned, there is no further
alignment for larger integers.
* langref: add some more "see also" links for atomics
* Add the following AIR instructions
- atomic_load
- atomic_store_unordered
- atomic_store_monotonic
- atomic_store_release
- atomic_store_seq_cst
- atomic_rmw
* Implement those AIR instructions in LLVM and C backends.
* AstGen: make the `ty` result locations for `@atomicRmw`, `@atomicLoad`,
and `@atomicStore` be `coerced_ty` to avoid unnecessary ZIR
instructions when Sema will be doing the coercions redundantly.
* Sema for `@atomicLoad` and `@atomicRmw` is done, however Sema for
`@atomicStore` is not yet implemented.
- comptime eval for `@atomicRmw` is not yet implemented.
* Sema: flesh out `coerceInMemoryAllowed` a little bit more. It can now
handle pointers.
* Implement Sema for `@cmpxchgWeak` and `@cmpxchgStrong`. Both runtime
and comptime codepaths are implement.
* Implement Codegen for LLVM backend and C backend.
* Add LazySrcLoc.node_offset_builtin_call_argX 3...5
* Sema: rework comptime control flow.
- `error.ComptimeReturn` is used to signal that a comptime function
call has returned a result (stored in the Inlining struct).
`analyzeCall` notices this and handles the result.
- The ZIR instructions `break_inline`, `block_inline`,
`condbr_inline` are now redundant and can be deleted. `break`,
`block`, and `condbr` function equivalently inside a comptime scope.
- The ZIR instructions `loop` and `repeat` also are modified to
directly perform comptime control flow inside a comptime scope,
skipping an unnecessary mechanism for analysis of runtime code.
This makes Zig perform closer to an interpreter when evaluating
comptime code.
* Sema: zirRetErrValue looks at Sema.ret_fn_ty rather than sema.func
for adding to the inferred error set. This fixes a bug for
inlined/comptime function calls.
* Implement ZIR printing for cmpxchg.
* stage1: make cmpxchg respect --single-threaded
- Our LLVM C++ API wrapper failed to expose this boolean flag before.
* Fix AIR printing for struct fields showing incorrect liveness data.
* Introduce `memoized_calls` to `Module` which stores all the comptime
function calls that are cached. It is keyed on the `*Fn` and the
comptime arguments, but it does not yet properly detect comptime function
pointers and avoid memoizing in this case. So it will have false
positives for when a comptime function call mutates data through a
pointer parameter.
* Sema: Add a new helper function: `resolveConstMaybeUndefVal`
* Value: add `enumToInt` method and use it in `zirEnumToInt`. It is
also used by the hashing function.
* Value: fix representation of optionals to match error unions.
Previously it would not handle nested optionals correctly. Now it
matches the memory layout of error unions and supports nested
optionals properly. This required changes in all the backends for
generating optional constants.
* TypedValue gains `eql` and `hash` methods.
* Value: Implement hashing for floats, optionals, and enums.
Additionally, the zig type tag is added to the hash, where it was not
previously, so that values of differing types will get different
hashes.
The big change in this commit is making `semaDecl` resolve the fields if
the Decl ends up being a struct or union. It needs to do this while
the `Sema` is still in scope, because it will have the resolved AIR
instructions that the field type expressions possibly reference. We do
this after the decl is populated and set to `complete` so that a `Decl`
may reference itself.
Everything else is fixes and improvements to make the test suite pass
again after making this change.
* New AIR instruction: `ptr_elem_ptr`
- Implemented for LLVM backend
* New Type tag: `type_info` which represents `std.builtin.TypeInfo`. It
is used by AstGen for the operand type of `@Type`.
* ZIR instruction `set_float_mode` uses `coerced_ty` to avoid
superfluous `as` instruction on operand.
* ZIR instruction `Type` uses `coerced_ty` to properly handle result
location type of operand.
* Fix two instances of `enum_nonexhaustive` Value Tag not handled
properly - it should generally be handled the same as `enum_full`.
* Fix struct and union field resolution not copying Type and Value
objects into its Decl arena.
* Fix enum tag value resolution discarding the ZIR=>AIR instruction map
for the child Sema, when they still needed to be accessed.
* Fix `zirResolveInferredAlloc` use-after-free in the AIR instructions
data array.
* Fix `elemPtrArray` not respecting const/mutable attribute of pointer
in the result type.
* Fix LLVM backend crashing when `updateDeclExports` is called before
`updateDecl`/`updateFunc` (which is, according to the API, perfectly
legal for the frontend to do).
* Fix LLVM backend handling element pointer of pointer-to-array. It
needed another index in the GEP otherwise LLVM saw the wrong type.
* Fix LLVM test cases not returning 0 from main, causing test failures.
Fixes a regression introduced in
6a5094872f10acc629543cc7f10533b438d0283a.
* Implement comptime shift-right.
* Implement `@Type` for integers and `@TypeInfo` for integers.
* Implement union initialization syntax.
* Implement `zirFieldType` for unions.
* Implement `elemPtrArray` for a runtime-known operand.
* Make `zirLog2IntType` support RHS of shift being `comptime_int`. In
this case it returns `comptime_int`.
The motivating test case for this commit was originally:
```zig
test "example" {
var l: List(10) = undefined;
l.array[1] = 1;
}
fn List(comptime L: usize) type {
var T = u8;
return struct {
array: [L]T,
};
}
```
However I changed it to:
```zig
test "example" {
var l: List = undefined;
l.array[1] = 1;
}
const List = blk: {
const T = [10]u8;
break :blk struct {
array: T,
};
};
```
Which ended up being a similar, smaller problem. The former test case
will require a similar solution in the implementation of comptime
function calls - checking if the result of the function call is a struct
or union, and using the child `Sema` before it is destroyed to resolve
the fields.
* Value: rename `error_union` to `eu_payload` and clarify the intended
usage in the doc comments. The way error unions is represented with
Value is fixed to not have ambiguous values.
* Fix codegen for error union constants in all the backends.
* Implement the AIR instructions having to do with error unions in the
LLVM backend.
* New AIR instructions: ptr_add, ptr_sub, ptr_elem_val, ptr_ptr_elem_val
- See the doc comments for details.
* Sema: implement runtime pointer arithmetic.
* Sema: implement elem_val for many-pointers.
* Sema: support coercion from `*[N:s]T` to `[*]T`.
* Type: isIndexable handles many-pointers.
The `comptime_args` field of Fn has a clarified purpose:
For generic function instantiations, there is a `TypedValue` here
for each parameter of the function:
* Non-comptime parameters are marked with a `generic_poison` for the value.
* Non-anytype parameters are marked with a `generic_poison` for the type.
Sema now has a `fn_ret_ty` field. Doc comments reproduced here:
> When semantic analysis needs to know the return type of the function whose body
> is being analyzed, this `Type` should be used instead of going through `func`.
> This will correctly handle the case of a comptime/inline function call of a
> generic function which uses a type expression for the return type.
> The type will be `void` in the case that `func` is `null`.
Various places in Sema are modified in accordance with this guidance.
Fixed `resolveMaybeUndefVal` not returning `error.GenericPoison` when
Value Tag of `generic_poison` is encountered.
Fixed generic function memoization incorrect equality checking. The
logic now clearly deals properly with any combination of anytype and
comptime parameters.
Fixed not removing generic function instantiation from the table in case
a compile errors in the rest of `call` semantic analysis. This required
introduction of yet another adapter which I have called
`GenericRemoveAdapter`. This one is nice and simple - it's the same hash
function (the same precomputed hash is passed in) but the equality
function checks pointers rather than doing any logic.
Inline/comptime function calls coerce each argument in accordance with
the function parameter type expressions. Likewise the return type
expression is evaluated and provided (see `fn_ret_ty` above).
There's a new compile error "unable to monomorphize function". It's
pretty unhelpful and will need to get improved in the future. It happens
when a type expression in a generic function did not end up getting
resolved at a callsite. This can happen, for example, if a runtime
parameter is attempted to be used where it needed to be comptime known:
```zig
fn foo(x: anytype) [x]u8 { _ = x; }
```
In this example, even if we pass a number such as `10` for `x`, it is
not marked `comptime`, so `x` will have a runtime known value, making
the return type unable to resolve.
In the LLVM backend I implement cmp instructions for float types to pass
some behavior tests that used floats.
* ZIR encoding for function instructions have a body for the return
type. This lets Sema for generic functions do the same thing it does
for parameters, handling `error.GenericPoison` in the evaluation of
the return type by marking the function as generic.
* Sema: fix missing block around the new Decl arena finalization. This
led to a memory corruption.
* Added some floating point support to the LLVM backend but didn't get
far enough to pass any new tests.
* The `indexable_ptr_len` ZIR instruction now uses a `none_or_ref`
ResultLoc. This prevents an unnecessary `ref` instruction from being
emitted.
* Sema: Fix `analyzeCall` using the incorrect ZIR object for the
generic function callee.
* LLVM backend: `genTypedValue` supports a `Slice` type encoded with
the `decl_ref` `Value`.
AstGen result locations now have a `coerced_ty` tag which is the same as
`ty` except it assumes that Sema will do a coercion, so it does not
redundantly add an `as` instruction into the ZIR code. This results in
cleaner ZIR and about a 14% reduction of ZIR bytes.
param and param_comptime ZIR instructions now have a block body for
their type expressions. This allows Sema to skip evaluation of the
block in the case that the parameter is comptime-provided. It also
allows a new mechanism to function: when evaluating type expressions of
generic functions, if it would depend on another parameter, it returns
`error.GenericPoison` which bubbles up and then is caught by the
param/param_comptime instruction and then handled.
This allows parameters to be evaluated independently so that the type
info for functions which have comptime or anytype parameters will still
have types populated for parameters that do not depend on values of
previous parameters (because evaluation of their param blocks will return
successfully instead of `error.GenericPoison`).
It also makes iteration over the block that contains function parameters
slightly more efficient since it now only contains the param
instructions.
Finally, it fixes the case where a generic function type expression contains
a function prototype. Formerly, this situation would cause shared state
to clobber each other; now it is in a proper tree structure so that
can't happen. This fix also required adding a field to Sema
`comptime_args_fn_inst` to make sure that the `comptime_args` field
passed into Sema is applied to the correct `func` instruction.
Source location for `node_offset_asm_ret_ty` is fixed; it was pointing at
the asm output name rather than the return type as intended.
Generic function instantiation is fixed, notably with respect to
parameter type expressions that depend on previous parameters, and with
respect to types which must be always comptime-known. This involves
passing all the comptime arguments at a callsite of a generic function,
and allowing the generic function semantic analysis to coerce the values
to the proper types (since it has access to the evaluated parameter type
expressions) and then decide based on the type whether the parameter is
runtime known or not. In the case of explicitly marked `comptime`
parameters, there is a check at the semantic analysis of the `call`
instruction.
Semantic analysis of `call` instructions does type coercion on the
arguments, which is needed both for generic functions and to make up for
using `coerced_ty` result locations (mentioned above).
Tasks left in this branch:
* Implement the memoization table.
* Add test coverage.
* Improve error reporting and source locations for compile errors.
After this change, the frontend and backend cooperate to keep track of
which Decls are actually emitted into the machine code. When any backend
sees a `decl_ref` Value, it must mark the corresponding Decl `alive`
field to true.
This prevents unused comptime data from spilling into the output object
files. For example, if you do an `inline for` loop, previously, any
intermediate value calculations would have gone into the object file.
Now they are garbage collected immediately after the owner Decl has its
machine code generated.
In the frontend, when it is time to send a Decl to the linker, if it has
not been marked "alive" then it is deleted instead.
Additional improvements:
* Resolve type ABI layouts after successful semantic analysis of a
Decl. This is needed so that the backend has access to struct fields.
* Sema: fix incorrect logic in resolveMaybeUndefVal. It should return
"not comptime known" instead of a compile error for global variables.
* `Value.pointerDeref` now returns `null` in the case that the pointer
deref cannot happen at compile-time. This is true for global
variables, for example. Another example is if a comptime known
pointer has a hard coded address value.
* Binary arithmetic sets the requireRuntimeBlock source location to the
lhs_src or rhs_src as appropriate instead of on the operator node.
* Fix LLVM codegen for slice_elem_val which had the wrong logic for
when the operand was not a pointer.
As noted in the comment in the implementation of deleteUnusedDecl, a
future improvement will be to rework the frontend/linker interface to
remove the frontend's responsibility of calling allocateDeclIndexes.
I discovered some issues with the plan9 linker backend that are related
to this, and worked around them for now.
* AIR no longer has a `variables` array. Instead of the `varptr`
instruction, Sema emits a constant with a `decl_ref`.
* AIR no longer has a `ref` instruction. There is no longer any
instruction that takes a value and returns a pointer to it. If this
is desired, Sema must either create an anynomous Decl and return a
constant `decl_ref`, or in the case of a runtime value, emit an
`alloc` instruction, `store` the value to it, and then return the
`alloc`.
* The `ref_val` Value Tag is eliminated. `decl_ref` should be used
instead. Also added is `eu_payload_ptr` which points to the payload
of an error union, given an error union pointer.
In general, Sema should avoid calling `analyzeRef` if it can be helped.
For example in the case of field_val and elem_val, there should never be
a reason to create a temporary (alloc or decl). Recent previous commits
made progress along that front.
There is a new abstraction in Sema, which looks like this:
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
// here 'anon_decl.arena()` may be used
const decl = try anon_decl.finish(ty, val);
// decl is typically now used with `decl_ref`.
This pattern is used to upgrade `ref_val` usages to `decl_ref` usages.
Additional improvements:
* Sema: fix source location resolution for calling convention
expression.
* Sema: properly report "unable to resolve comptime value" for loads of
global variables. There is now a set of functions which can be
called if the callee wants to obtain the Value even if the tag is
`variable` (indicating comptime-known address but runtime-known value).
* Sema: `coerce` resolves builtin types before checking equality.
* Sema: fix `u1_type` missing from `addType`, making this type have a
slightly more efficient representation in AIR.
* LLVM backend: fix `genTypedValue` for tags `decl_ref` and `variable`
to properly do an LLVMConstBitCast.
* Remove unused parameter from `Value.toEnum`.
After this commit, some test cases are no longer passing. This is due to
the more principled approach to comptime references causing more
anonymous decls to get sent to the linker for codegen. However, in all
these cases the decls are not actually referenced by the runtime machine
code. A future commit in this branch will implement garbage collection
of decls so that unused decls do not get sent to the linker for codegen.
This will make the tests go back to passing.
Frontend improvements:
* When compiling in `zig test` mode, put a task on the work queue to
analyze the main package root file. Normally, start code does
`_ = import("root");` to make Zig analyze the user's code, however in
the case of `zig test`, the root source file is the test runner.
Without this change, no tests are picked up.
* In the main pipeline, once semantic analysis is finished, if there
are no compile errors, populate the `test_functions` Decl with the
set of test functions picked up from semantic analysis.
* Value: add `array` and `slice` Tags.
LLVM backend improvements:
* Fix incremental updates of globals. Previously the
value of a global would not get replaced with a new value.
* Fix LLVM type of arrays. They were incorrectly sending
the ABI size as the element count.
* Remove the FuncGen parameter from genTypedValue. This function is for
generating global constants and there is no function available when
it is being called.
- The `ref_val` case is now commented out. I'd like to eliminate
`ref_val` as one of the possible Value Tags. Instead it should
always be done via `decl_ref`.
* Implement constant value generation for slices, arrays, and structs.
* Constant value generation for functions supports the `decl_ref` tag.
* Add AIR instruction: struct_field_val
- This is part of an effort to eliminate the AIR instruction `ref`.
- It's implemented for C backend and LLVM backend so far.
* Rename `resolvePossiblyUndefinedValue` to `resolveMaybeUndefVal` just
to save some columns on long lines.
* Sema: add `fieldVal` alongside `fieldPtr` (renamed from
`namedFieldPtr`). This is part of an effort to eliminate the AIR
instruction `ref`. The idea is to avoid unnecessary loads, stores,
stack usage, and IR instructions, by paying a DRY cost.
LLVM backend improvements:
* internal linkage vs exported linkage is implemented, along with
aliases. There is an issue with incremental updates due to missing
LLVM API for deleting aliases; see the relevant comment in this commit.
- `updateDeclExports` is hooked up to the LLVM backend now.
* Fix usage of `Type.tag() == .noreturn` rather than calling `isNoReturn()`.
* Properly mark global variables as mutable/constant.
* Fix llvm type generation of function pointers
* Fix codegen for calls of function pointers
* Implement llvm type generation of error unions and error sets.
* Implement AIR instructions: addwrap, subwrap, mul, mulwrap, div,
bit_and, bool_and, bit_or, bool_or, xor, struct_field_ptr,
struct_field_val, unwrap_errunion_err, add for floats, sub for
floats.
After this commit, `zig test` on a file with `test "example" {}`
correctly generates and executes a test binary. However the
`test_functions` slice is undefined and just happens to be going into
the .bss section, causing the length to be 0. The next step towards
`zig test` will be replacing the `test_functions` Decl Value with the
set of test function pointers, before it is sent to linker/codegen.
* properly set global variables to const if they are not a global
variable.
* implement global variable initializations.
* initial implementation of llvmType() for structs and functions.
* implement genTypedValue for variable tags
* implement more AIR instructions: varptr, slice_ptr, slice_len,
slice_elem_val, ptr_slice_elem_val, unwrap_errunion_payload,
unwrap_errunion_payload_ptr, unwrap_errunion_err,
unwrap_errunion_err_ptr.
These AIR instructions are the next blockers for `zig test` to work for
this backend.
After this commit, the "hello world" x86_64 test case passes for the
LLVM backend as well.
* Added doc comments for `std.Target.ObjectFormat` enum
* `std.Target.oFileExt` is removed because it is incorrect for Plan-9
targets. Instead, use `std.Target.ObjectFormat.fileExt` and pass a
CPU architecture.
* Added `Compilation.Directory.joinZ` for when a null byte is desired.
* Improvements to `Compilation.create` logic for computing `use_llvm`
and reporting errors in contradictory flags. `-femit-llvm-ir` and
`-femit-llvm-bc` will now imply `-fLLVM`.
* Fix compilation when passing `.bc` files on the command line.
* Improvements to the stage2 LLVM backend:
- cleaned up error messages and error reporting. Properly bubble up
some errors rather than dumping to stderr; others turn into panics.
- properly call ZigLLVMCreateTargetMachine and
ZigLLVMTargetMachineEmitToFile and implement calculation of the
respective parameters (cpu features, code model, abi name, lto,
tsan, etc).
- LLVM module verification only runs in debug builds of the compiler
- use LLVMDumpModule rather than printToString because in the case
that we incorrectly pass a null pointer to LLVM it may crash during
dumping the module and having it partially printed is helpful in
this case.
- support -femit-asm, -fno-emit-bin, -femit-llvm-ir, -femit-llvm-bc
- Support LLVM backend when used with Mach-O and WASM linkers.
to the link infrastructure, instead of being stored with Module.Fn. This
moves towards a strategy to make more efficient use of memory by not
storing Air or Liveness data in the Fn struct, but computing it on
demand, immediately sending it to the backend, and then immediately
freeing it.
Backends which want to defer codegen until flush() such as SPIR-V
must move the Air/Liveness data upon `updateFunc` being called and keep
track of that data in the backend implementation itself.