Merge branch 'trunk' into report-problems

This commit is contained in:
Richard Feldman 2020-04-01 23:12:31 -04:00 committed by GitHub
commit 63bf1ce8b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 254 additions and 5 deletions

4
Cargo.lock generated
View File

@ -568,6 +568,10 @@ dependencies = [
"roc_types", "roc_types",
] ]
[[package]]
name = "roc_builtins_bitcode"
version = "0.1.0"
[[package]] [[package]]
name = "roc_can" name = "roc_can"
version = "0.1.0" version = "0.1.0"

View File

@ -10,6 +10,7 @@ members = [
"compiler/types", "compiler/types",
"compiler/uniq", "compiler/uniq",
"compiler/builtins", "compiler/builtins",
"compiler/builtins/bitcode",
"compiler/constrain", "compiler/constrain",
"compiler/unify", "compiler/unify",
"compiler/solve", "compiler/solve",

View File

@ -8,7 +8,9 @@ use inkwell::passes::PassManager;
use inkwell::types::BasicType; use inkwell::types::BasicType;
use inkwell::OptimizationLevel; use inkwell::OptimizationLevel;
use roc_collections::all::ImMap; use roc_collections::all::ImMap;
use roc_gen::llvm::build::{build_proc, build_proc_header, get_call_conventions}; use roc_gen::llvm::build::{
build_proc, build_proc_header, get_call_conventions, module_from_builtins,
};
use roc_gen::llvm::convert::basic_type_from_layout; use roc_gen::llvm::convert::basic_type_from_layout;
use roc_mono::expr::{Expr, Procs}; use roc_mono::expr::{Expr, Procs};
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
@ -65,7 +67,7 @@ fn gen(src: &str, target: Triple, dest_filename: &Path) {
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var); let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
let context = Context::create(); let context = Context::create();
let module = context.create_module("app"); let module = module_from_builtins(&context, "app");
let builder = context.create_builder(); let builder = context.create_builder();
let fpm = PassManager::create(&module); let fpm = PassManager::create(&module);

View File

@ -0,0 +1,10 @@
[package]
name = "roc_builtins_bitcode"
version = "0.1.0"
authors = ["Richard Feldman <richard.t.feldman@gmail.com>"]
repository = "https://github.com/rtfeldman/roc"
readme = "README.md"
edition = "2018"
description = "Generate LLVM bitcode for Roc builtins"
license = "Apache-2.0"

View File

@ -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!

View File

@ -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: &[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";

View File

@ -0,0 +1,10 @@
#![crate_type = "lib"]
#![no_std]
// TODO replace this with a normal Inkwell build_cast call - this was just
// used as a proof of concept for getting bitcode importing working!
#[no_mangle]
pub fn i64_to_f64_(num: i64) -> f64 {
num as f64
}

View File

@ -2,6 +2,7 @@ use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use inkwell::builder::Builder; use inkwell::builder::Builder;
use inkwell::context::Context; use inkwell::context::Context;
use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::{Linkage, Module}; use inkwell::module::{Linkage, Module};
use inkwell::passes::PassManager; use inkwell::passes::PassManager;
use inkwell::types::{BasicTypeEnum, IntType, StructType}; use inkwell::types::{BasicTypeEnum, IntType, StructType};
@ -9,6 +10,7 @@ use inkwell::values::BasicValueEnum::{self, *};
use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue}; use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::{FloatPredicate, IntPredicate}; use inkwell::{FloatPredicate, IntPredicate};
use crate::llvm::builtins::BUILTINS_BITCODE;
use crate::llvm::convert::{ use crate::llvm::convert::{
basic_type_from_layout, collection_wrapper, empty_collection, get_fn_type, ptr_int, basic_type_from_layout, collection_wrapper, empty_collection, get_fn_type, ptr_int,
}; };
@ -47,6 +49,13 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
} }
} }
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
let memory_buffer = MemoryBuffer::create_from_memory_range(BUILTINS_BITCODE, module_name);
Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err))
}
pub fn add_passes(fpm: &PassManager<FunctionValue<'_>>) { pub fn add_passes(fpm: &PassManager<FunctionValue<'_>>) {
// tail-call elimination is always on // tail-call elimination is always on
fpm.add_instruction_combining_pass(); fpm.add_instruction_combining_pass();
@ -1069,6 +1078,31 @@ fn call_with_args<'a, 'ctx, 'env>(
BasicValueEnum::IntValue(int_val) BasicValueEnum::IntValue(int_val)
} }
Symbol::NUM_TO_FLOAT => {
// TODO specialize this to be not just for i64!
let builtin_fn_name = "i64_to_f64_";
let fn_val = env
.module
.get_function(builtin_fn_name)
.unwrap_or_else(|| panic!("Unrecognized builtin function: {:?} - if you're working on the Roc compiler, do you need to rebuild the bitcode? See compiler/builtins/bitcode/README.md", builtin_fn_name));
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
for (arg, _layout) in args.iter() {
arg_vals.push(*arg);
}
let call = env
.builder
.build_call(fn_val, arg_vals.into_bump_slice(), "call_builtin");
call.set_call_convention(DEFAULT_CALLING_CONVENTION);
call.try_as_basic_value()
.left()
.unwrap_or_else(|| panic!("LLVM error: Invalid call for builtin {:?}", symbol))
}
Symbol::FLOAT_EQ => { Symbol::FLOAT_EQ => {
debug_assert!(args.len() == 2); debug_assert!(args.len() == 2);

View File

@ -0,0 +1,81 @@
// GENERATED FILE - NEVER EDIT BY HAND!
//
// See compiler/builtins/bitcode/README.md for how to generate.
pub const BUILTINS_BITCODE: &[u8] = &[
66, 67, 192, 222, 53, 20, 0, 0, 14, 0, 0, 0, 98, 12, 48, 28, 1, 199, 10, 172, 96, 11, 173, 144,
7, 110, 0, 7, 110, 16, 7, 109, 32, 15, 245, 48, 15, 244, 208, 6, 113, 224, 6, 116, 32, 7, 110,
0, 7, 109, 48, 15, 244, 16, 14, 226, 192, 14, 229, 32, 68, 1, 50, 5, 0, 0, 0, 0, 33, 12, 0, 0,
88, 1, 0, 0, 11, 2, 33, 0, 2, 0, 0, 0, 22, 0, 0, 0, 7, 129, 35, 145, 65, 200, 4, 73, 6, 16, 50,
57, 146, 1, 132, 12, 37, 5, 8, 25, 30, 4, 139, 98, 128, 12, 69, 2, 66, 146, 11, 66, 100, 16,
50, 20, 56, 8, 24, 75, 10, 50, 50, 136, 72, 112, 196, 33, 35, 68, 18, 135, 140, 16, 65, 146, 2,
100, 200, 8, 177, 20, 32, 67, 70, 136, 32, 201, 1, 50, 50, 132, 24, 42, 40, 42, 144, 49, 124,
176, 92, 145, 32, 195, 200, 0, 0, 0, 137, 32, 0, 0, 12, 0, 0, 0, 50, 34, 200, 8, 32, 100, 133,
4, 147, 33, 164, 132, 4, 147, 33, 227, 132, 161, 144, 20, 18, 76, 134, 140, 11, 132, 100, 76,
16, 28, 67, 0, 115, 4, 160, 80, 4, 132, 52, 16, 48, 71, 0, 6, 35, 0, 0, 0, 81, 24, 0, 0, 23, 0,
0, 0, 27, 252, 32, 248, 255, 255, 255, 255, 1, 128, 3, 64, 2, 30, 128, 2, 194, 128, 128, 7,
121, 120, 7, 113, 40, 135, 54, 152, 7, 122, 8, 135, 113, 88, 7, 224, 23, 126, 65, 30, 234, 97,
30, 232, 225, 23, 224, 65, 30, 222, 65, 28, 202, 97, 30, 232, 33, 28, 198, 97, 29, 0, 130, 30,
194, 65, 30, 206, 161, 28, 232, 161, 13, 198, 1, 30, 234, 1, 192, 7, 60, 176, 131, 54, 176, 3,
58, 0, 0, 0, 0, 0, 73, 24, 0, 0, 1, 0, 0, 0, 19, 130, 0, 0, 19, 48, 124, 192, 3, 59, 248, 5,
59, 160, 131, 54, 168, 7, 119, 88, 7, 119, 120, 135, 123, 112, 135, 54, 96, 135, 116, 112, 135,
122, 192, 135, 54, 56, 7, 119, 168, 135, 13, 101, 80, 14, 109, 208, 14, 122, 80, 14, 109, 144,
14, 118, 64, 7, 122, 96, 7, 116, 208, 6, 230, 128, 7, 112, 160, 7, 113, 32, 7, 120, 208, 6,
238, 128, 7, 122, 16, 7, 118, 160, 7, 115, 32, 7, 122, 96, 7, 116, 208, 6, 179, 16, 7, 114,
128, 7, 26, 33, 76, 14, 199, 64, 254, 30, 127, 197, 245, 52, 155, 158, 118, 207, 191, 226, 52,
125, 252, 38, 151, 93, 180, 115, 45, 45, 207, 177, 213, 173, 241, 185, 238, 130, 13, 169, 128,
69, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 0, 0, 88, 0, 137, 13, 2, 69, 189, 2, 0, 0, 178, 64, 6, 0, 0,
0, 50, 30, 152, 12, 25, 17, 76, 144, 140, 9, 38, 71, 198, 4, 67, 106, 57, 20, 65, 9, 0, 0, 0,
0, 177, 24, 0, 0, 137, 0, 0, 0, 51, 8, 128, 28, 196, 225, 28, 102, 20, 1, 61, 136, 67, 56, 132,
195, 140, 66, 128, 7, 121, 120, 7, 115, 152, 113, 12, 230, 0, 15, 237, 16, 14, 244, 128, 14,
51, 12, 66, 30, 194, 193, 29, 206, 161, 28, 102, 48, 5, 61, 136, 67, 56, 132, 131, 27, 204, 3,
61, 200, 67, 61, 140, 3, 61, 204, 120, 140, 116, 112, 7, 123, 8, 7, 121, 72, 135, 112, 112, 7,
122, 112, 3, 118, 120, 135, 112, 32, 135, 25, 204, 17, 14, 236, 144, 14, 225, 48, 15, 110, 48,
15, 227, 240, 14, 240, 80, 14, 51, 16, 196, 29, 222, 33, 28, 216, 33, 29, 194, 97, 30, 102, 48,
137, 59, 188, 131, 59, 208, 67, 57, 180, 3, 60, 188, 131, 60, 132, 3, 59, 204, 240, 20, 118,
96, 7, 123, 104, 7, 55, 104, 135, 114, 104, 7, 55, 128, 135, 112, 144, 135, 112, 96, 7, 118,
40, 7, 118, 248, 5, 118, 120, 135, 119, 128, 135, 95, 8, 135, 113, 24, 135, 114, 152, 135, 121,
152, 129, 44, 238, 240, 14, 238, 224, 14, 245, 192, 14, 236, 48, 3, 98, 200, 161, 28, 228, 161,
28, 204, 161, 28, 228, 161, 28, 220, 97, 28, 202, 33, 28, 196, 129, 29, 202, 97, 6, 214, 144,
67, 57, 200, 67, 57, 152, 67, 57, 200, 67, 57, 184, 195, 56, 148, 67, 56, 136, 3, 59, 148, 195,
47, 188, 131, 60, 252, 130, 59, 212, 3, 59, 176, 195, 12, 199, 105, 135, 112, 88, 135, 114,
112, 131, 116, 104, 7, 120, 96, 135, 116, 24, 135, 116, 160, 135, 25, 206, 83, 15, 238, 0, 15,
242, 80, 14, 228, 144, 14, 227, 64, 15, 225, 32, 14, 236, 80, 14, 51, 32, 40, 29, 220, 193, 30,
194, 65, 30, 210, 33, 28, 220, 129, 30, 220, 224, 28, 228, 225, 29, 234, 1, 30, 102, 24, 81,
56, 176, 67, 58, 156, 131, 59, 204, 80, 36, 118, 96, 7, 123, 104, 7, 55, 96, 135, 119, 120, 7,
120, 152, 81, 76, 244, 144, 15, 240, 80, 14, 51, 30, 106, 30, 202, 97, 28, 232, 33, 29, 222,
193, 29, 126, 1, 30, 228, 161, 28, 204, 33, 29, 240, 97, 6, 84, 133, 131, 56, 204, 195, 59,
176, 67, 61, 208, 67, 57, 252, 194, 60, 228, 67, 59, 136, 195, 59, 176, 195, 140, 197, 10, 135,
121, 152, 135, 119, 24, 135, 116, 8, 7, 122, 40, 7, 114, 152, 129, 92, 227, 16, 14, 236, 192,
14, 229, 80, 14, 243, 48, 35, 193, 210, 65, 30, 228, 225, 23, 216, 225, 29, 222, 1, 30, 102,
72, 25, 59, 176, 131, 61, 180, 131, 27, 132, 195, 56, 140, 67, 57, 204, 195, 60, 184, 193, 57,
200, 195, 59, 212, 3, 60, 204, 72, 180, 113, 8, 7, 118, 96, 7, 113, 8, 135, 113, 88, 135, 25,
219, 198, 14, 236, 96, 15, 237, 224, 6, 240, 32, 15, 229, 48, 15, 229, 32, 15, 246, 80, 14,
110, 16, 14, 227, 48, 14, 229, 48, 15, 243, 224, 6, 233, 224, 14, 228, 80, 14, 248, 0, 0, 0, 0,
121, 32, 0, 0, 27, 0, 0, 0, 114, 30, 72, 32, 67, 136, 12, 25, 9, 114, 50, 72, 32, 35, 129, 140,
145, 145, 209, 68, 160, 16, 40, 100, 60, 49, 50, 66, 142, 144, 33, 163, 40, 16, 24, 0, 201, 2,
0, 0, 80, 73, 67, 32, 76, 101, 118, 101, 108, 82, 116, 76, 105, 98, 85, 115, 101, 71, 79, 84,
35, 8, 69, 48, 130, 80, 8, 35, 8, 197, 48, 195, 48, 4, 196, 12, 3, 33, 20, 50, 18, 152, 160,
140, 216, 216, 236, 218, 92, 218, 222, 200, 234, 216, 202, 92, 204, 216, 194, 206, 230, 70, 17,
10, 3, 0, 0, 0, 169, 24, 0, 0, 11, 0, 0, 0, 11, 10, 114, 40, 135, 119, 128, 7, 122, 88, 112,
152, 67, 61, 184, 195, 56, 176, 67, 57, 208, 195, 130, 230, 28, 198, 161, 13, 232, 65, 30, 194,
193, 29, 230, 33, 29, 232, 33, 29, 222, 193, 29, 0, 209, 16, 0, 0, 6, 0, 0, 0, 7, 204, 60, 164,
131, 59, 156, 3, 59, 148, 3, 61, 160, 131, 60, 148, 67, 56, 144, 195, 1, 0, 0, 0, 97, 32, 0, 0,
8, 0, 0, 0, 19, 4, 65, 6, 176, 13, 194, 129, 0, 0, 0, 0, 3, 0, 0, 0, 70, 48, 52, 20, 115, 0,
133, 52, 1, 209, 4, 0, 0, 0, 0, 0, 161, 32, 0, 0, 16, 0, 0, 0, 163, 4, 199, 80, 1, 32, 170, 0,
33, 50, 132, 136, 16, 33, 66, 196, 8, 137, 26, 64, 136, 12, 33, 34, 68, 136, 16, 49, 66, 82,
14, 16, 34, 99, 132, 196, 188, 32, 68, 134, 136, 17, 18, 242, 128, 16, 25, 66, 82, 90, 16, 34,
100, 132, 10, 0, 16, 40, 0, 0, 0, 0, 0, 0, 113, 32, 0, 0, 3, 0, 0, 0, 50, 14, 16, 34, 132, 0,
194, 2, 0, 0, 0, 0, 139, 138, 191, 252, 105, 31, 31, 88, 17, 135, 229, 53, 128, 231, 83, 204,
67, 1, 116, 229, 220, 21, 133, 255, 102, 211, 221, 20, 0, 0, 0, 0, 101, 12, 0, 0, 31, 0, 0, 0,
18, 3, 148, 240, 0, 0, 0, 0, 2, 0, 0, 0, 11, 0, 0, 0, 24, 0, 0, 0, 76, 0, 0, 0, 1, 0, 0, 0, 88,
0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 1, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 24, 0, 0,
0, 59, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 255, 255, 255, 255, 0,
52, 0, 0, 0, 0, 0, 0, 93, 12, 0, 0, 27, 0, 0, 0, 18, 3, 148, 190, 0, 0, 0, 0, 105, 54, 52, 95,
116, 111, 95, 102, 54, 52, 95, 57, 46, 48, 46, 49, 45, 114, 117, 115, 116, 45, 49, 46, 52, 50,
46, 48, 45, 115, 116, 97, 98, 108, 101, 120, 56, 54, 95, 54, 52, 45, 117, 110, 107, 110, 111,
119, 110, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 114, 111, 99, 95, 98, 117, 105, 108,
116, 105, 110, 115, 95, 98, 105, 116, 99, 111, 100, 101, 46, 52, 103, 53, 105, 114, 57, 108,
106, 45, 99, 103, 117, 46, 48, 0, 0, 0, 0, 0, 0,
];

View File

@ -1,2 +1,3 @@
pub mod build; pub mod build;
pub mod builtins;
pub mod convert; pub mod convert;

View File

@ -344,4 +344,17 @@ mod gen_builtins {
i64 i64
); );
} }
#[test]
fn int_to_float() {
assert_evals_to!(
indoc!(
r#"
Num.toFloat 0x9
"#
),
9.0,
f64
);
}
} }

View File

@ -10,7 +10,7 @@ macro_rules! assert_llvm_evals_to {
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var); let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
let context = Context::create(); let context = Context::create();
let module = context.create_module("app"); let module = roc_gen::llvm::build::module_from_builtins(&context, "app");
let builder = context.create_builder(); let builder = context.create_builder();
let fpm = inkwell::passes::PassManager::create(&module); let fpm = inkwell::passes::PassManager::create(&module);
@ -142,7 +142,7 @@ macro_rules! assert_opt_evals_to {
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var); let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
let context = Context::create(); let context = Context::create();
let module = context.create_module("app"); let module = roc_gen::llvm::build::module_from_builtins(&context, "app");
let builder = context.create_builder(); let builder = context.create_builder();
let fpm = PassManager::create(&module); let fpm = PassManager::create(&module);

View File

@ -15,7 +15,7 @@ in our imaginations...so Rube Goldberg it is!)
1. `cd` into `examples/hello-world/` 1. `cd` into `examples/hello-world/`
2. Run `cargo run hello.roc` to compile the Roc source code into a `hello.o` file. 2. Run `cargo run hello.roc` to compile the Roc source code into a `hello.o` file.
3. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!) 3. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!)
4. Move `libhello_from_roc.so` onto the system library path, e.g. with `sudo mv libhello_from_roc.so /usr/local/lib/` 4. Move `libhello_from_roc.so` onto the system library path, e.g. with `sudo mv libhello_from_roc.so /usr/local/lib/` on macOS, or `sudo mv libhello_from_roc.so /usr/local/lib /usr/lib` on Linux.
5. Run `rustc host.rs -o hello` to generate the `hello` executable. 5. Run `rustc host.rs -o hello` to generate the `hello` executable.
6. Run `./hello` to see the greeting! 6. Run `./hello` to see the greeting!