roc/crates/compiler/builtins/bitcode
Brendan Hansknecht f901946455
Improve roc atomic refcounting by using first bit to indicate threadlocal
By avoiding atomic refcounting for any threadlocal variable, this greatly improves performance.
Leads to the performance of threadlocal refcounting being only ~4% behind non-atomic refcounting.
The old atomic refcounting could be as far as ~50% behind (though normally 10-20%).

This does not enable anything atomic related.
If we enable all forms of data loading (List.get, Box.unbox, loading recursive tag) to propagate the atomic flag,
this should be a reasonable implementation for roc by default.
With propagation, a platform would just set a list to atomic. On load, individual elements would also get set to atomic.
We also should probably revert back to threadlocal if an atomic refcount drops to 1.
2024-12-31 20:52:03 -08:00
..
bc expand zig nix workaround and update issue number 2024-12-11 21:31:56 -08:00
src Improve roc atomic refcounting by using first bit to indicate threadlocal 2024-12-31 20:52:03 -08:00
.gitignore add fuzzing script 2024-07-28 20:33:46 -07:00
build.rs bitcode build fix (#7394) 2024-12-20 11:38:56 -08:00
build.zig wasm does not like PIC 2024-12-12 17:45:31 -08:00
Cargo.toml update to workspace deps for miscellaneous 2024-11-29 11:37:39 +11:00
fuzz_in_tmux.sh watch afl status 2024-07-28 20:33:46 -07:00
README.md Kevin Gillette: markdown typo fixes 2023-04-10 14:07:03 -06:00
run-tests.sh improve comments zig tests, set up zig tests in CI 2022-08-19 17:14:49 +02:00
run-wasm-tests.sh builtins: build the Wasm interpreter from inside run-wasm-tests.sh 2022-12-16 16:05:00 +00:00

Bitcode for Builtins

Adding a bitcode builtin

To add a builtin:

  1. Add the function to the relevant module. For Num builtin use it in src/num.zig, for Str builtins use src/str.zig, and so on. For anything you add, you must add tests for it! Not only does to make the builtins more maintainable, it's the the easiest way to test these functions on Zig. To run the test, run: zig build test
  2. Make sure the function is public with the pub keyword and uses the C calling convention. This is really easy, just add pub and callconv(.C) to the function declaration like so: pub fn atan(num: f64) callconv(.C) f64 { ... }
  3. In src/main.zig, export the function. This is also organized by module. For example, for a Num function find the Num section and add: comptime { exportNumFn(num.atan, "atan"); }. The first argument is the function, the second is the name of it in LLVM.
  4. In compiler/builtins/src/bitcode.rs, add a constant for the new function. This is how we use it in Rust. Once again, this is organized by module, so just find the relevant area and add your new function.
  5. You can now use your function in Rust using call_bitcode_fn in llvm/src/build.rs!

How it works

Roc's builtins are implemented in the compiler using LLVM only. When their implementations are simple enough (e.g. addition), they can be implemented directly in Inkwell.

When their implementations are complex enough, it's nicer to implement them in a higher-level language like Zig, then compile the result to LLVM bitcode, and import that bitcode into the compiler.

Compiling the bitcode happens automatically in a Rust build script at compiler/builtins/build.rs. Then builtins/src/bitcode/rs statically imports the compiled bitcode for use in the compiler.

You can find the compiled bitcode in target/debug/build/roc_builtins-[some random characters]/out/builtins.bc. There will be two directories like roc_builtins-[some random characters], look for the one that has an out directory as a child.

The bitcode is a bunch of bytes that aren't particularly human-readable. If you want to take a look at the human-readable LLVM IR, look at compiler/builtins/bitcode/builtins.ll

Calling bitcode functions

Use the call_bitcode_fn function defined in llvm/src/build.rs to call bitcode functions.