Here's what I think the ZIR should be. AstGen is not yet implemented to
match this, and the main implementation of analyzeSwitch in Sema is not
yet implemented to match it either.
Here are some example byte size reductions from master branch, with the
ZIR memory layout from this commit:
```
switch (foo) {
a => 1,
b => 2,
c => 3,
d => 4,
}
```
184 bytes (master) => 40 bytes (this branch)
```
switch (foo) {
a, b => 1,
c..d, e, f => 2,
g => 3,
else => 4,
}
```
240 bytes (master) => 80 bytes (this branch)
This makes a few changes to the base64 codecs.
* The padding character is optional. The common "URL-safe" variant, in
particular, is generally not used with padding. This is also the case for
password hashes, so having this will avoid code duplication with bcrypt,
scrypt and other functions.
* The URL-safe variant is added. Instead of having individual constants
for each parameter of each variant, we are now grouping these in a
struct. So, `standard_pad_char` just becomes `standard.pad_char`.
* Types are not `snake_case`'d any more. So, `standard_encoder` becomes
`standard.Encoder`, as it is a type.
* Creating a decoder with ignored characters required the alphabet and
padding. Now, `standard.decoderWithIgnore(<ignored chars>)` returns a
decoder with the standard parameters and the set of ignored chars.
* Whatever applies to `standard.*` obviously also works with `url_safe.*`
* the `calcSize()` interface was inconsistent, taking a length in the
encoder, and a slice in the encoder. Rename the variant that takes a
slice to `calcSizeForSlice()`.
* In the decoder with ignored characters, add `calcSizeUpperBound()`,
which is more useful than the one that takes a slice in order to size
a fixed buffer before we have the data.
* Return `error.InvalidCharacter` when the input actually contains
characters that are neither padding nor part of the alphabet. If we
hit a padding issue (which includes extra bits at the end),
consistently return `error.InvalidPadding`.
* Don't keep the `char_in_alphabet` array permanently in a decoder;
it is only required for sanity checks during initialization.
* Tests are unchanged, but now cover both the standard (padded) and
the url-safe (non-padded) variants.
* Add an error set, rename `OutputTooSmallError` to `NoSpaceLeft`
to match the `hex2bin` equivalent.
Also fixed abiAlignment - for pointers it was returning the abi
alignment inside the type, rather than of the pointer itself. There is
now `ptrAlignment` for getting the alignment inside the type of
pointers.
* zir.Code: introduce a decls array. This is so that `decl_val` and
`decl_ref` instructions can refer to a Decl with a u32 and therefore
they can also store a source location. This is needed for proper
compile error reporting.
* astgen uses a hash map to avoid redundantly adding a Decl to the
decls array.
* fixed reporting "instruction illegal outside function body" instead
of the desired message "unable to resolve comptime value".
* astgen skips emitting dbg_stmt instructions in comptime scopes.
* astgen has some logic to avoid adding unnecessary type coercion
instructions for common values.
Introduce "inline" variants of ZIR tags:
* block => block_inline
* repeat => repeat_inline
* break => break_inline
* condbr => condbr_inline
The inline variants perform control flow at compile-time, and they
utilize the return value of `Sema.analyzeBody`.
`analyzeBody` now returns an Index, not a Ref, which is the ZIR index of
a break instruction. This effectively communicates both the intended
break target block as well as the operand, allowing parent blocks to
find out whether they, in turn, should return the break instruction up the
call stack, or accept the operand as the block's result and continue
analyzing instructions in the block.
Additionally:
* removed the deprecated ZIR tag `block_comptime`.
* removed `break_void_node` so that all break instructions use the same Data.
* zir.Code: remove the `root_start` and `root_len` fields. There is now
implied to be a block at index 0 for the root body. This is so that
`break_inline` has something to point at and we no longer need the
special instruction `break_flat`.
* implement source location byteOffset() for .node_offset_if_cond
.node_offset_for_cond is probably redundant and can be deleted.
We don't have `comptime var` supported yet, so this commit adds a test
that at least makes sure the condition is required to be comptime known
for `inline while`.
* Module.addBreak and addBreakVoid return zir.Inst.Index not Ref
because Index is the simpler type and we never need a Ref for these.
* astgen: make noreturn stuff return the unreachable_value and avoid
unnecessary calls to rvalue()
* breakExpr: avoid unnecessary access into the tokens array
* breakExpr: fix incorrect `@intCast` (previously this unsafely
casted an Index to a Ref)
Change some ZIR instructions from un_tok to un_node. Idea here is to
avoid needlessly accessing the tokens array.
Go ahead and finish the catch code in orelseCatchExpr. Otherwise it
would be an easy mistake to get the scopes wrong when updating that
code and introduce a bug.
Delete a function that is now dead code.
* Introduce helper functions on Module.WipZirCode and zir.Code
* Move some logic around
* re-introduce ref_start_index
* prefer usize for local variables + `@intCast` at the end.
Empirically this is easier to optimize.
* Avoid using mem.{bytesAsSlice,sliceAsBytes} because it incurs an
unnecessary multiplication/division which may cause problems for the
optimizer.
* Use a regular enum, not packed, for `Ref`. Memory layout is
guaranteed for enums which specify their tag type. Packed enums have
ABI alignment of 1 byte which is too small.
This provides us greatly increased type safety and prevents the common
mistake of using a zir.Inst.Ref where a zir.Inst.Index was expected or
vice-versa. It also increases the ergonomics of using the typed values
which can be directly referenced with a Ref over the previous zir.Const
approach.
The main pain point is casting between a []Ref and []u32, which could be
alleviated in the future with a new std.mem function.
This is useful for build.zig files to check in some cases, for example
to adhere to the convention of installing config to /etc instead of
/usr/etc on linux when using the /usr prefix. Perhaps std.build will
handle such common cases eventually, but that is not yet the case.
* comment out the failing stage2 test cases
(so that we can uncomment the ones that are newly passing with
further commits)
* Sema: implement negate, negatewrap
* astgen: implement field access, multiline string literals, and
character literals
* Module: when resolving an AST node into a byte offset, use the
main_tokens array, not the firstToken function