| Age | Commit message (Collapse) | Author |
|
this was pretty low hanging fruit
|
|
|
|
There are some `@panic("TODO")` in there but I'm trying to get the
branch to the point where collaborators can jump in.
Next is to repair the seam between LazySrcLoc and codegen's expected
absolute file offsets.
|
|
Next up is reworking the seam between the LazySrcLoc emitted by Sema
and the byte offsets currently expected by codegen.
And then the big one: updating astgen.zig to use the new memory layout.
|
|
The memory layout for ZIR instructions is completely reworked. See
zir.zig for those changes. Some new types:
* `zir.Code`: a "finished" set of ZIR instructions. Instead of allocating
each instruction independently, there is now a Tag and 8 bytes of
data available for all ZIR instructions. Small instructions fit
within these 8 bytes; larger ones use 4 bytes for an index into
`extra`. There is also `string_bytes` so that we can have 4 byte
references to strings. `zir.Inst.Tag` describes how to interpret
those 8 bytes of data.
- This is shared by all `Block` scopes.
* `Module.WipZirCode`: represents an in-progress `zir.Code`. In this
structure, the arrays are mutable, and get resized as we add/delete
things. There is extra state to keep track of things. This struct is
stored on the stack. Once it is finished, it produces an immutable
`zir.Code`, which will remain on the heap for the duration of a
function's existence.
- This is shared by all `GenZir` scopes.
* `Sema`: represents in-progress semantic analysis of a `zir.Code`.
This data is stored on the stack and is shared among all `Block`
scopes. It is now the main "self" argument to everything in the file
that was previously named `zir_sema.zig`.
Additionally, I moved some logic that was in `Module` into here.
`Module.Fn` now stores its parameter names inside the `zir.Code`,
instead of inside ZIR instructions. When the TZIR memory layout
reworking time comes, codegen will be able to reference this data
directly instead of duplicating it.
astgen.zig is (so far) almost entirely untouched, but nearly all of it
will need to be reworked to adhere to this new memory layout structure.
I have no benchmarks to report yet, as I am still working through
compile errors and fixing various things that I broke in this branch.
Overhaul of Source Locations:
Previously we used `usize` everywhere to mean byte offset, but sometimes
also mean other stuff. This was error prone and also made us do
unnecessary work, and store unnecessary bytes in memory.
Now there are more types involved into source locations, and more ways
to describe a source location.
* AllErrors.Message: embrace the assumption that files always have less
than 2 << 32 bytes.
* SrcLoc gets more complicated, to model more complicated source
locations.
* Introduce LazySrcLoc, which can model interesting source locations
with very little stored state. Useful for avoiding doing unnecessary
work when no compile errors occur.
Also, previously, we had `src: usize` on every ZIR instruction. This is
no longer the case. Each instruction now determines whether it even cares
about source location, and if so, how that source location is stored.
This requires more careful work inside `Sema`, but it results in fewer
bytes stored on the heap, without compromising accuracy and power of
compile error messages.
Miscellaneous:
* std.zig: string literals have more helpful result values for
reporting errors. There is now a lower level API and a higher level
API.
- side note: I noticed that the string literal logic needs some love.
There is some unnecessarily hacky code there.
* cut & pasted some TZIR logic that was in zir.zig to ir.zig. This
probably broke stuff and needs to get fixed.
* Removed type/Enum.zig, type/Union.zig, and type/Struct.zig. I don't
think this quite how this code will be organized. Need some more
careful planning about how to implement structs, unions, enums. They
need to be independent Decls, just like a top level function.
|
|
The modification to the grammar in the comment is in line with the
grammar in the zig-spec repo.
Note: checking if the previous token is a colon is insufficent to tell
if a block has a label, the identifier must be checked for as well. This
can be seen in sentinel terminated slicing: `foo[0..1:{}]`
|
|
|
|
Fixes a regression from #7920.
|
|
* Now it supports being an lvalue (see additional lines in the test
case).
* Properly handles a pointer result location (see additional lines in
the test case that assign the result of the orelse to a variable
rather than a const).
* Properly sets the result location type when possible, so that type
inference of an `orelse` operand expression knows its result type.
|
|
We can now codegen optionals! This includes the following instructions:
- is_null
- is_null_ptr
- is_non_null
- is_non_null_ptr
- optional_payload
- optional_payload_ptr
- br_void
Also includes a test for optionals.
|
|
|
|
|
|
|
|
All stage2 tests are passing again in this branch.
Remaining checklist for this branch:
* get the rest of the zig fmt test cases passing
- re-enable the translate-c test case that is blocking on this
* implement the 2 `@panic(TODO)`'s in parse.zig
* use fn_proto not fn_decl for extern function declarations
|
|
Make translate-c use intermediate AST
|
|
Now it builds and what remains in this branch is:
* fix the stage2 compiler regressions from this branch
* finish the rest of zig fmt test cases, get them passing
* Merge in Vexu's translate-c AST branch & fix translate-c regressions
|
|
more progress on converting astgen to the new AST memory layout.
only a few code paths left to update.
|
|
|
|
|
|
Now all that is left is compile errors and whatever regressions this
branch introduced.
|
|
|
|
additionally introduce a new file to centralize all the data about
builtin functions that we have, including:
* enum tag identifying the builtin function
* number of parameters.
* whether the expression may need a memory location.
* whether the expression allows an lvalue (currently only true for
`@field`).
Now there is only one ComptimeStringMap that has this data as the value,
and we dispatch on the enum tag in order to asgen the builtin function.
In particular this simplifies the logic for checking the number of
parameters.
This removes some untested code paths from if and while, which need to
be restored with #7929 in mind.
After this there are only a handful left of expression types to rework
to the new memory layout, and then it will be only compile errors left
to solve.
|
|
break, continue, blocks, bit_not, negation, identifiers, string
literals, integer literals, inline assembly
also gave multiline string literals a different node tag from regular
string literals, for code clarity and to avoid an unnecessary load from
token_tags array.
|
|
|
|
|
|
The astgen for switch expressions did not respect the ZIR rules of only
referencing instructions that are in scope:
%14 = block_comptime_flat({
%15 = block_comptime_flat({
%16 = const(TypedValue{ .ty = comptime_int, .val = 1})
})
%17 = block_comptime_flat({
%18 = const(TypedValue{ .ty = comptime_int, .val = 2})
})
})
%19 = block({
%20 = ref(%5)
%21 = deref(%20)
%22 = switchbr(%20, [%15, %17], {
%15 => {
%23 = const(TypedValue{ .ty = comptime_int, .val = 1})
%24 = store(%10, %23)
%25 = const(TypedValue{ .ty = void, .val = {}})
%26 = break("label_19", %25)
},
%17 => {
%27 = const(TypedValue{ .ty = comptime_int, .val = 2})
%28 = store(%10, %27)
%29 = const(TypedValue{ .ty = void, .val = {}})
%30 = break("label_19", %29)
}
}, {
%31 = unreachable_safe()
}, special_prong=else)
})
In this snippet you can see that the comptime expr referenced %15 and
%17 which are not in scope. There also was no test coverage for runtime
switch expressions.
Switch expressions will have to be re-introduced to follow these rules
and with some test coverage. There is some usable code being deleted in
this commit; it will be useful to reference when re-implementing switch
later.
A few more improvements to do while we're at it:
* only use .ref result loc on switch target if any prongs obtain the
payload with |*syntax|
- this improvement should be done to if, while, and for as well.
- this will remove the needless ref/deref instructions above
* remove switchbr and add switch_block, which is both a block and a
switch branch.
- similarly we should remove loop and add loop_block.
This commit introduces a "force_comptime" flag into the GenZIR
scope. The main purpose of this will be to choose the "comptime"
variants of certain key zir instructions, such as function calls and
branches. We will be moving away from using the block_comptime_flat
ZIR instruction, and eventually deleting it.
This commit also contains miscellaneous fixes to this branch that bring
it to the state of passing all the tests.
|
|
|
|
|
|
|
|
|
|
|
|
Local variable declarations now detect whether the result location for the
initialization expression consumes the result location as a pointer. If
it does, then the local is emitted as a LocalPtr. Otherwise it is
emitted as a LocalVal.
This results in clean, straightforward ZIR code for semantic analysis.
|
|
|
|
Motivating test case:
```zig
export fn _start() noreturn {
var x: u64 = 1;
var y: u32 = 2;
var thing: u32 = 1;
const result = if (thing == 1) x else y;
exit();
}
```
The main idea here is for astgen to output ideal ZIR depending on
whether or not the sub-expressions of a block consume the result
location. Here, neither `x` nor `y` consume the result location of the
conditional expression block, and so the ZIR should communicate the
result of the condbr using break instructions, not with the result
location pointer.
With this commit, this is accomplished:
```
%22 = alloc_inferred()
%23 = block({
%24 = const(TypedValue{ .ty = type, .val = bool})
%25 = deref(%18)
%26 = const(TypedValue{ .ty = comptime_int, .val = 1})
%27 = cmp_eq(%25, %26)
%28 = as(%24, %27)
%29 = condbr(%28, {
%30 = deref(%4)
< there is no longer a store instruction here >
%31 = break("label_23", %30)
}, {
%32 = deref(%11)
< there is no longer a store instruction here >
%33 = break("label_23", %32)
})
})
%34 = store_to_inferred_ptr(%22, %23) <-- the store is only here
%35 = resolve_inferred_alloc(%22)
```
However if the result location gets consumed, the break instructions
change to break_void, and the result value is communicated only by the
stores, not by the break instructions.
Implementation:
* The GenZIR scope that conditional branches uses now has an optional
result location pointer field and a count of how many times the
result location ended up being an rvalue (not consumed).
* When rvalue() is called on a result location for a block, it
increments this counter. After generating the branches of a block,
astgen for the conditional branch checks this count and if it is 2
then the store_to_block_ptr instructions are elided and it calls
rvalue() using the block result (which will account for peer type
resolution on the break operands).
astgen has many functions disabled until they can be reworked with these
new semantics. That will be done before merging the branch.
There are some new rules for astgen to follow regarding result locations
and what you are allowed/required to do depending on which one is passed
to expr(). See the updated doc comments of ResultLoc for details.
I also changed naming conventions of stuff in this commit, sorry about
that.
|
|
|
|
The following AST avoids unnecessary derefs now:
* error set decl
* field access
* array access
* for loops: replace ensure_indexable and deref on the len_ptr with a
special purpose ZIR instruction called indexable_ptr_len.
Added an error note when for loop operand is the wrong type.
I also accidentally implemented `@field`.
|
|
* fix wrong pointer const-ness when unwrapping optionals
* allow grouped expressions and orelse as lvalues
* ZIR for unwrapping optionals: no redundant deref
- add notes to please don't use rlWrapPtr, this function should be
deleted
* catch and orelse: better ZIR for non-lvalue: no redundant deref;
operate entirely on values. lvalue case still works properly.
- properly propagate the result location into the target expression
* Test harness: better output when tests fail due to compile errors.
* TZIR: add instruction variants. These allow fewer TZIR instructions to
be emitted from zir_sema. See the commit diff for per-instruction
documentation.
- is_null
- is_non_null
- is_null_ptr
- is_non_null_ptr
- is_err
- is_err_ptr
- optional_payload
- optional_payload_ptr
* TZIR: removed old naming convention instructions:
- isnonnull
- isnull
- iserr
- unwrap_optional
* ZIR: add instruction variants. These allow fewer ZIR instructions to
be emitted from astgen. See the commit diff for per-instruction
documentation.
- is_non_null
- is_null
- is_non_null_ptr
- is_null_ptr
- is_err
- is_err_ptr
- optional_payload_safe
- optional_payload_unsafe
- optional_payload_safe_ptr
- optional_payload_unsafe_ptr
- err_union_payload_safe
- err_union_payload_unsafe
- err_union_payload_safe_ptr
- err_union_payload_unsafe_ptr
- err_union_code
- err_union_code_ptr
* ZIR: removed old naming convention instructions:
- isnonnull
- isnull
- iserr
- unwrap_optional_safe
- unwrap_optional_unsafe
- unwrap_err_safe
- unwrap_err_unsafe
- unwrap_err_code
|
|
There was just some untested code that did not work. .isnull -> .isnonnull
and I had to add a .ref resultloc to make types match up.
|
|
Also fix incorrectly destroying notes.
This work is based on Vexu's patch in #7555.
|
|
* Implement error notes
- note: other symbol exported here
- note: previous else prong is here
- note: previous '_' prong is here
* Add Compilation.CObject.ErrorMsg. This object properly converts to
AllErrors.Message when the time comes.
* Add Compilation.CObject.failure_retryable. Properly handles
out-of-memory and other transient failures.
* Introduce Module.SrcLoc which has not only a byte offset but also
references the file which the byte offset applies to.
* Scope.Block now contains both a pointer to the "owner" Decl and the
"source" Decl. As an example, during inline function call, the
"owner" will be the Decl of the caller and the "source" will be the
Decl of the callee.
* Module.ErrorMsg now sports a `file_scope` field so that notes can
refer to source locations in a file other than the parent error
message.
* Some instances where a `*Scope` was stored, now store a
`*Scope.Container`.
* Some methods in the `Scope` namespace were moved to the more specific
type, since there was only an implementation for one particular tag.
- `removeDecl` moved to `Scope.Container`
- `destroy` moved to `Scope.File`
* Two kinds of Scope deleted:
- zir_module
- decl
* astgen: properly use DeclVal / DeclRef. DeclVal was incorrectly
changed to be a reference; this commit fixes it. Fewer ZIR
instructions processed as a result.
- declval_in_module is renamed to declval
- previous declval ZIR instruction is deleted; it was only for .zir
files.
* Test harness: friendlier diagnostics when an unexpected set of errors
is encountered.
* zir_sema: fix analyzeInstBlockFlat by properly calling resolvingInst
on the last zir instruction in the block.
Compile log implementation:
* Write to a buffer rather than directly to stderr.
* Only keep track of 1 callsite per Decl.
* No longer mutate the ZIR Inst struct data.
* "Compile log statement found" errors are only emitted when there are
no other compile errors.
-femit-zir and support for .zir source files is regressed. If we wanted
to support this again, outputting .zir would need to be done as yet
another backend rather than in the haphazard way it was previously
implemented.
For parsing .zir, it was implemented previously in a way that was not
helpful for debugging. We need tighter integration with the test harness
for it to be useful; so clearly a rewrite is needed. Given that a
rewrite is needed, and it was getting in the way of progress and
organization of the rest of stage2, I regressed the feature.
|
|
|
|
|
|
* extract magic number into a constant
* properly use result location casting for the operand
* naming convention for ZIR instructions
|
|
`@setEvalBranchQuota` can be called before the comptime/inline call
stack is created.
For example:
```zig
@setEvalBranchQuota(100);
comptime {
while (true) {}
}
```
Here we need to set the branch_quota before the comptime block creates a
scope for the branch_count.
|
|
* Function calls that happen in a comptime scope get called at
compile-time. We do this by putting the parameters in place as
constant values and then running regular function analysis on the
body.
* Added `Scope.Block.dump()` for debugging purposes.
* Fixed some code to call `identifierTokenString` rather than
`tokenSlice`, making it work for `@""` syntax.
* Implemented `Value.copy` for big integers.
Follow-up issues to tackle:
* Adding compile errors to the callsite instead of the callee Decl.
* Proper error notes for "called from here".
- Related: #7555
* Branch quotas.
* ZIR support?
|
|
|
|
|
|
|
|
|
|
|