Commit Graph

93 Commits

Author SHA1 Message Date
Meghan Denny
e878a6633f stage2: implement runtime % and @rem 2021-08-30 00:31:40 -07:00
Jacob G-W
4ac37eb484 stage2 Air: add struct_field_ptr_index_{0..3}
Since these are very common, it will save memory.
2021-08-21 23:52:55 -04:00
Andrew Kelley
f378b0adce stage2: comptime function with the same args is memoized
* 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.
2021-08-21 20:47:42 -07:00
Andrew Kelley
0cd361219c stage2: field type expressions support referencing locals
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
   6a5094872f.

 * 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.
2021-08-20 15:41:57 -07:00
Jacob G-W
2e6ce11eb2 stage2: implement shr and boilerplate for shl
This implements it in the llvm and c backends.
x86_64 will have to be a little more work.
2021-08-19 16:18:40 -04:00
Andrew Kelley
799fedf612 stage2: pass some error union tests
* 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.
2021-08-07 20:34:28 -07:00
Andrew Kelley
f81b2531cb stage2: pass some pointer tests
* 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.
2021-08-07 15:46:53 -07:00
Andrew Kelley
ddf14323ea stage2: implement @truncate 2021-08-01 16:13:58 -07:00
Andrew Kelley
040c6eaaa0 stage2: garbage collect unused anon decls
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.
2021-07-29 19:30:37 -07:00
Andrew Kelley
a5c6e51f03 stage2: more principled approach to comptime references
* 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.
2021-07-29 15:59:51 -07:00
Andrew Kelley
dc88864c97 stage2: implement @boolToInt
This is the first commit in which some behavior tests are passing for
both stage1 and stage2.
2021-07-27 17:08:37 -07:00
Andrew Kelley
31a59c229c stage2: improvements towards zig test
* 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.
2021-07-26 19:27:49 -07:00
Andrew Kelley
7b8cb881df stage2: improvements towards zig test
* There is now a main_pkg in addition to root_pkg. They are usually the
   same. When using `zig test`, main_pkg is the user's source file and
   root_pkg has the test runner.
 * scanDecl no longer looks for test decls outside the package being
   tested. honoring `--test-filter` is still TODO.
 * test runner main function has a void return value rather than
   `anyerror!void`
 * Sema is improved to generate better AIR for for loops on slices.
 * Sema: fix incorrect capacity calculation in zirBoolBr
 * Sema: add compile errors for trying to use slice fields as an lvalue.
 * Sema: fix type coercion for error unions
 * Sema: fix analyzeVarRef generating garbage AIR
 * C codegen: fix renderValue for error unions with 0 bit payload
 * C codegen: implement function pointer calls
 * CLI: fix usage text

 Adds 4 new AIR instructions:

  * slice_len, slice_ptr: to get the ptr and len fields of a slice.
  * slice_elem_val, ptr_slice_elem_val: to get the element value of
    a slice, and a pointer to a slice.

AstGen gains a new functionality:

 * One of the unused flags of struct decls is now used to indicate
   structs that are known to have non-zero size based on the AST alone.
2021-07-23 22:42:31 -07:00
Andrew Kelley
f47cf93b47 stage2: C backend: fix ret AIR instruction
when operand has 0 runtime bits
2021-07-20 15:56:42 -07:00
Andrew Kelley
9c652cc650 stage2: C backend: implement support for switch_br AIR 2021-07-20 15:52:58 -07:00
Jacob G-W
414b144257 cbe: fix not (it is a ty_op, not un_op) 2021-07-20 12:19:16 -07:00
Andrew Kelley
4a0f38bb76 stage2: update LLVM backend to new AIR memory layout
Also fix compile errors when not using -Dskip-non-native
2021-07-20 12:19:16 -07:00
Andrew Kelley
761f36ff93 stage2: rework C backend for new AIR memory layout 2021-07-20 12:19:16 -07:00
Andrew Kelley
c09b973ec2 stage2: compile error fixes for AIR memory layout branch
Now the branch is compiling again, provided that one uses
`-Dskip-non-native`, but many code paths are disabled. The code paths
can now be re-enabled one at a time and updated to conform to the new
AIR memory layout.
2021-07-20 12:19:16 -07:00
Andrew Kelley
0f38f68696 stage2: Air and Liveness are passed ephemerally
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.
2021-07-20 12:19:16 -07:00
Andrew Kelley
5d6f7b44c1 stage2: rework AIR memory layout
This commit changes the AIR file and the documentation of the memory
layout. The actual work of modifying the surrounding code (in Sema and
codegen) is not yet done.
2021-07-20 12:18:14 -07:00
Andrew Kelley
28dd9d478d C backend: TypedefMap is now ArrayHashMap
The C backend depends on insertion order into this map so that type
definitions will be declared before they are used.
2021-07-12 12:40:32 -07:00
Andrew Kelley
9dbe684854 C backend: cleanups to wrapping int operations
* less branching by passing parameters in the main op code switch.
 * properly pass the target when asking the type system for int info.
 * handle u8, i16, etc when it is represented using
   int_unsigned/int_signed tag.
 * compile error instead of assertion failure for unimplemented cases
   (greater than 64 bits integer).
 * control flow cleanups
 * zig.h: expand macros into inline functions
 * reduce the complexity of the test case by making it one test case
   that calls multiple functions. Also fix the problem of c_int max
   value mismatch between host and target.
2021-07-08 11:21:06 -07:00
Matt Knight
fb16633ecb C backend: add/sub/mul wrapping for the C backend 2021-07-08 09:56:40 -07:00
Andrew Kelley
c2e66d9bab stage2: basic inferred error set support
* Inferred error sets are stored in the return Type of the function,
   owned by the Module.Fn. So it cleans up that memory in deinit().
 * Sema: update the inferred error set in zirRetErrValue
   - Update relevant code in wrapErrorUnion
 * C backend: improve some some instructions to take advantage of
   liveness analysis to avoid being emitted when unused.
 * C backend: when an error union has a payload type with no runtime
   bits, emit the error union as the same type as the error set.
2021-07-07 20:47:21 -07:00
Andrew Kelley
5c8bd443d9 stage2: fix if expressions on error unions
AstGen had the then-else logic backwards for if expressions
on error unions. This commit fixes it.

Turns out AstGen only really needs `is_non_null` and `is_non_err`,
and does not need the `is_null` or `is_err` variants. So I removed the
`is_null{,_ptr}` and `is_err{,_ptr}` ZIR instructions (-4) and
added `is_non_err`, `is_non_err_ptr` ZIR instructions (+2) for
a total of (-2) ZIR instructions, giving us a tiny bit more headroom
within the 256 tag limit. This required swapping the order of
then/else blocks in a handful of cases, but ultimately means the
ZIR will be in the same as source order, which is convenient
when debugging.

AIR code on the other hand, gains the `is_non_err` and `is_non_err_ptr`
instructions.

Sema: fix logic in zirErrUnionCode and zirErrUnionCodePtr returning the
wrong result type.
2021-07-07 19:50:56 -07:00
Andrew Kelley
13f04e3012 stage2: implement @panic and beginnigs of inferred error sets
* ZIR: add two instructions:
   - ret_err_value_code
   - ret_err_value
 * AstGen: add countDefers and utilize it to emit more efficient ZIR for
   return expressions in the presence of defers.
 * AstGen: implement |err| payloads for `errdefer` syntax.
   - There is not an "unused capture" error for it yet.
 * AstGen: `return error.Foo` syntax gets a hot path in return
   expressions, using the new ZIR instructions. This also is part of
   implementing inferred error sets, since we need to tell Sema to add
   an error value to the inferred error set before it gets coerced.
 * Sema: implement `@setCold`.
   - Implement `@setCold` support for C backend.
 * `@panic` and regular safety panics such as `unreachable` now properly
   invoke `std.builtin.panic`.
 * C backend: improve pointer and function value rendering.
 * C linker: fix redundant typedefs.
 * Add Type.error_set_inferred.
 * Fix Value.format for enum_literal, enum_field_index, bytes.
 * Remove the C backend test that checks for identical text

I measured a 14% reduction in Total ZIR Bytes from master branch
for std/os.zig.
2021-07-07 00:39:23 -07:00
Jacob G-W
9fffffb07b fix code broken from previous commit 2021-06-21 17:03:03 -07:00
Jacob G-W
641ecc260f std, src, doc, test: remove unused variables 2021-06-21 17:03:03 -07:00
Jacob G-W
a95fdb0635 stage2: simplify codegen for errorToInt and intToError
We can just use bitcast instead of error_to_int, int_to_error since
errorToInt and intToError do not actually do anything, just change types.
This allows us to remove 2 air ops that were the exact same as bitcast
2021-06-21 18:45:28 +03:00
Martin Wickham
fc9430f567 Breaking hash map changes for 0.8.0
- hash/eql functions moved into a Context object
- *Context functions pass an explicit context
- *Adapted functions pass specialized keys and contexts
- new getPtr() function returns a pointer to value
- remove functions renamed to fetchRemove
- new remove functions return bool
- removeAssertDiscard deleted, use assert(remove(...)) instead
- Keys and values are stored in separate arrays
- Entry is now {*K, *V}, the new KV is {K, V}
- BufSet/BufMap functions renamed to match other set/map types
- fixed iterating-while-modifying bug in src/link/C.zig
2021-06-03 17:02:16 -05:00
joachimschmidt557
e8236551ab stage2: Move BlockData out of ir.Inst.Block 2021-05-22 21:15:25 -04:00
Andrew Kelley
79dee75b1c stage2: rename ir.zig to air.zig
We've settled on the nomenclature for the artifacts the compiler
pipeline produces:

1. Tokens
2. AST (Abstract Syntax Tree)
3. ZIR (Zig Intermediate Representation)
4. AIR (Analyzed Intermediate Representation)
5. Machine Code

Renaming `ir` identifiers to `air` will come with the inevitable
air-memory-layout branch that I plan to start after the 0.8.0 release.
2021-05-22 14:29:16 -07:00
Andrew Kelley
a74632b50a C backend: fix emitting '$' in identifier names
This causes warnings from clang when compiled.
2021-05-11 14:51:21 -07:00
Andrew Kelley
bcf15e39e2 stage2: add owns_tv flag to Module.Decl
Decl objects need to know whether they are the owner of the Type/Value
associated with them, in order to decide whether to destroy the
associated Namespace, Fn, or Var when cleaning up.
2021-05-11 14:17:52 -07:00
Andrew Kelley
f86469bc5e stage2: semaDecl properly analyzes the decl block
Also flattened out Decl TypedValue fields into
ty, val, has_tv
and add relevant fields to Decl for alignment and link section.
2021-04-28 16:57:01 -07:00
Andrew Kelley
4630e3891c AstGen: implement inline asm output 2021-04-19 18:44:59 -07:00
Andrew Kelley
9f744f19e7 Merge pull request #8464 from gracefuu/grace/wasm-ops
stage2 wasm: Add division and bitwise/boolean ops &, |, ^, and, or
2021-04-08 13:41:49 -07:00
gracefu
4c71942f84 stage2: Add .div to ir.zig 2021-04-08 05:26:56 +08:00
Andrew Kelley
015599d1ef C backend: enumerate all the types in renderType
Now that we're close to supporting all the types, get rid of the `else`
prong and explicitly list out those types that are not yet implemented.

Thanks @g-w1
2021-04-07 13:17:23 -07:00
Andrew Kelley
19cf987198 C backend: implement Enum types and values
They are lowered directly as the integer tag type, with no typedef.
2021-04-06 23:19:46 -07:00
Andrew Kelley
97d7fddfb7 stage2: progress towards basic structs
Introduce `ResultLoc.none_or_ref` which is used by field access
expressions to avoid unnecessary loads when the field access itself
will do the load. This turns:

```zig
p.y - p.x - p.x
```

from

```zir
  %14 = load(%4) node_offset:8:12
  %15 = field_val(%14, "y") node_offset:8:13
  %16 = load(%4) node_offset:8:18
  %17 = field_val(%16, "x") node_offset:8:19
  %18 = sub(%15, %17) node_offset:8:16
  %19 = load(%4) node_offset:8:24
  %20 = field_val(%19, "x") node_offset:8:25
```

to

```zir
  %14 = field_val(%4, "y") node_offset:8:13
  %15 = field_val(%4, "x") node_offset:8:19
  %16 = sub(%14, %15) node_offset:8:16
  %17 = field_val(%4, "x") node_offset:8:25
```

Much more compact. This requires `Sema.zirFieldVal` to support both
pointers and non-pointers.

C backend: Implement typedefs for struct types, as well as the following
TZIR instructions:
 * mul
 * mulwrap
 * addwrap
 * subwrap
 * ref
 * struct_field_ptr

Note that add, addwrap, sub, subwrap, mul, mulwrap instructions are all
incorrect currently and need to be updated to properly handle wrapping
and non wrapping for signed and unsigned.

C backend: change indentation delta to 1, to make the output smaller and
to process fewer bytes.

I promise I will add a test case as soon as I fix those warnings that
are being printed for my test case.
2021-04-02 19:11:51 -07:00
jacob gw
0005b34637 stage2: implement sema for @errorToInt and @intToError 2021-03-28 18:22:01 -07:00
Andrew Kelley
bd2154da3d stage2: the code is compiling again
(with a lot of things commented out)
2021-03-18 22:48:28 -07:00
Andrew Kelley
b2682237db stage2: get Module and Sema compiling again
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.
2021-03-18 22:19:28 -07:00
Veikka Tuominen
fc62ff77c3 stage2: error union payload must also be a valid variable type 2021-03-08 00:33:59 +02:00
jacob gw
30ffa052f2 stage2 cbe: add error union and error union operations 2021-03-08 00:33:59 +02:00
Veikka Tuominen
0a7be71bc2 stage2 cbe: non pointer optionals 2021-03-08 00:33:56 +02:00
Veikka Tuominen
cfc19eace7 stage2 cbe: errors 2021-03-08 00:33:07 +02:00
Veikka Tuominen
c22f010fdd stage2 cbe: regular optional types 2021-03-08 00:33:07 +02:00