diff --git a/Cargo.lock b/Cargo.lock index 0bd136ae08..c0774939ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -568,6 +568,10 @@ dependencies = [ "roc_types", ] +[[package]] +name = "roc_builtins_bitcode" +version = "0.1.0" + [[package]] name = "roc_can" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9a713fbff2..07de563bac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "compiler/types", "compiler/uniq", "compiler/builtins", + "compiler/builtins/bitcode", "compiler/constrain", "compiler/unify", "compiler/solve", diff --git a/compiler/builtins/bitcode/Cargo.toml b/compiler/builtins/bitcode/Cargo.toml new file mode 100644 index 0000000000..29ec5e72e0 --- /dev/null +++ b/compiler/builtins/bitcode/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "roc_builtins_bitcode" +version = "0.1.0" +authors = ["Richard Feldman "] +repository = "https://github.com/rtfeldman/roc" +readme = "README.md" +edition = "2018" +description = "Generate LLVM bitcode for Roc builtins" +license = "Apache-2.0" + diff --git a/compiler/builtins/bitcode/README.md b/compiler/builtins/bitcode/README.md new file mode 100644 index 0000000000..1757864c88 --- /dev/null +++ b/compiler/builtins/bitcode/README.md @@ -0,0 +1,53 @@ +# Bitcode for Builtins + +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 Rust, compile the +result to LLVM bitcode, and import that bitcode into the compiler. + +Here is the process for doing that. + +## Building the bitcode + +The source we'll use to generate the bitcode is in `src/lib.rs` in this directory. + +To generate the bitcode, `cd` into `compiler/builtins/bitcode/` and run: + +```bash +$ cargo rustc --release --lib -- --emit=llvm-bc +``` + +Then look in the root `roc` source directory under `target/release/deps/` for a file +with a name like `roc_builtins_bitcode-8da0901c58a73ebf.bc` - except +probably with a different hash before the `.bc`. There should be only one `*.bc` file in that directory. + +> If you want to take a look at the human-readable LLVM IR rather than the +> bitcode, run this instead and look for a `.ll` file instead of a `.bc` file: +> +> ```bash +> $ cargo rustc --release --lib -- --emit=llvm-ir +> ``` + +## Importing the bitcode + +The bitcode is a bunch of bytes that aren't particularly human-readable. +Since Roc is designed to be distributed as a single binary, these bytes +need to be included in the raw source somewhere. + +We have a script that generates this file and writes it to stdout. +To use it, run this command, replacing `bitcode.bc` with the path to the +generated file in `target/release/deps/` from earlier. + +`$ ./import.pl bitcode.bc > ../../gen/src/llvm/builtins.rs` + +If the script succeeds, `git status` should show that the appropriate +`.rs` file has been updated. + +Before checking it in, make sure to run `cargo fmt` on the root of +the project! Otherwise that file will not be formatted properly and +will fail the build. + +Once you've formatted the `builtins.rs` file, check it in and you're done! diff --git a/compiler/builtins/bitcode/bitcode.bc b/compiler/builtins/bitcode/bitcode.bc new file mode 100644 index 0000000000..f0d79e6208 Binary files /dev/null and b/compiler/builtins/bitcode/bitcode.bc differ diff --git a/compiler/builtins/bitcode/import.pl b/compiler/builtins/bitcode/import.pl new file mode 100755 index 0000000000..2af8e2e7ef --- /dev/null +++ b/compiler/builtins/bitcode/import.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +$num_args = $#ARGV + 1; + +if ($num_args != 1) { + die "\nUsage: import.pl path-to-roc_builtins_bitcode-hashgoeshere.bc\n"; +} + +my $filename = $ARGV[0]; +my $before_bitcode = "// GENERATED FILE - NEVER EDIT BY HAND!\n//\n// See compiler/builtins/bitcode/README.md for how to generate.\n\npub const BUILTINS_BITCODE: &'static [u8] = &[\n "; +my $after_bitcode = "\n];"; + +# Get a filehandle to the raw binary data in the file +open(my $fh, '<:raw', $filename) + or die "Could not open file '$filename'\n\n$!"; + +my $bitcode = ''; + +while (1) { + # Read 1 byte + my $success = read $fh, my $byte, 1; + + if (not defined $success) { + # Explode on error. + die $! + } elsif (not $success) { + # Exit the loop if no bytes were read. + last; + } else { + if (length($bitcode) > 0) { + $bitcode .= ', '; + } + + # Print the numeric representation of the byte + $bitcode .= ord($byte); + } +} +close $fh; + +print "$before_bitcode$bitcode$after_bitcode\n"; diff --git a/compiler/builtins/bitcode/src/lib.rs b/compiler/builtins/bitcode/src/lib.rs new file mode 100644 index 0000000000..52a6f2d8e0 --- /dev/null +++ b/compiler/builtins/bitcode/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub fn i64_to_f64_(num: i64) -> f64 { + num as f64 +}