mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Resolve conflicts
This commit is contained in:
commit
f2983f1360
19 changed files with 358 additions and 220 deletions
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
@ -56,6 +56,13 @@ jobs:
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
name: cargo test -- --ignored
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: -- --ignored
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
name: cargo test --release
|
name: cargo test --release
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,23 +1,37 @@
|
||||||
# Building the Roc compiler from source
|
# Building the Roc compiler from source
|
||||||
|
|
||||||
|
|
||||||
## Installing LLVM, valgrind, libunwind, and libc++-dev
|
## Installing LLVM, Zig, valgrind, libunwind, and libc++-dev
|
||||||
|
|
||||||
To build the compiler, you need these installed:
|
To build the compiler, you need these installed:
|
||||||
|
|
||||||
* `libunwind` (macOS should already have this one installed)
|
* `libunwind` (macOS should already have this one installed)
|
||||||
* `libc++-dev`
|
* `libc++-dev`
|
||||||
* [`zig`](https://ziglang.org/download/)
|
* a particular version of Zig (see below)
|
||||||
* a particular version of LLVM
|
* a particular version of LLVM (see below)
|
||||||
|
|
||||||
To run the test suite (via `cargo test`), you additionally need to install:
|
To run the test suite (via `cargo test`), you additionally need to install:
|
||||||
|
|
||||||
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)]
|
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
||||||
|
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
||||||
|
|
||||||
|
### libunwind & libc++-dev
|
||||||
|
|
||||||
|
MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`).
|
||||||
Some systems may already have `libc++-dev` on them, but if not, you may need to install it. (On Ubuntu, this can be done with `sudo apt-get install libc++-dev`.)
|
Some systems may already have `libc++-dev` on them, but if not, you may need to install it. (On Ubuntu, this can be done with `sudo apt-get install libc++-dev`.)
|
||||||
MacOS systems should already have `libunwind`, but other systems will need to install it (e.g. with `sudo apt-get install libunwind-dev`).
|
|
||||||
|
|
||||||
To install Zig on macOS, use `brew install zig`. To install on Ubuntu, checkout [zig's docs](https://github.com/dryzig/zig-debian/blob/master/README.md).
|
### Zig
|
||||||
|
We use a specific version of Zig, a build off the the commit `0088efc4b`. The latest tagged version of Zig, 0.6.0, doesn't include the feature to emit LLVM ir, which is a core feature of how we use Zig. To download this specific version, you can use the following links:
|
||||||
|
* [linux](https://ziglang.org/builds/zig-linux-x86_64-0.6.0+0088efc4b.tar.xz)
|
||||||
|
* [macOS](https://ziglang.org/builds/zig-macos-x86_64-0.6.0+0088efc4b.tar.xz)
|
||||||
|
|
||||||
|
Alternatively, any recent master branch build should work. To install the latest master branch build you can use:
|
||||||
|
* `brew install zig --HEAD` (on macos)
|
||||||
|
* `snap install zig --classic --edge` (on ubunutu)
|
||||||
|
|
||||||
|
Once 0.7.0 is released, we'll switch back to installing the tagged releases and this process will get easier.
|
||||||
|
|
||||||
|
### LLVM
|
||||||
|
|
||||||
To see which version of LLVM you need, take a look at `Cargo.toml`, in particular the `branch` section of the `inkwell` dependency. It should have something like `llvmX-Y` where X and Y are the major and minor revisions of LLVM you need.
|
To see which version of LLVM you need, take a look at `Cargo.toml`, in particular the `branch` section of the `inkwell` dependency. It should have something like `llvmX-Y` where X and Y are the major and minor revisions of LLVM you need.
|
||||||
|
|
||||||
|
|
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -2318,6 +2318,7 @@ dependencies = [
|
||||||
"roc_uniq",
|
"roc_uniq",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-xml-rs",
|
"serde-xml-rs",
|
||||||
|
"serial_test",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
@ -2804,6 +2805,28 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b15f74add9a9d4a3eb2bf739c9a427d266d3895b53d992c3a7c234fec2ff1f1"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot 0.10.2",
|
||||||
|
"serial_test_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65f59259be9fc1bf677d06cc1456e97756004a1a5a577480f71430bd7c17ba33"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.21",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.40",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha-1"
|
name = "sha-1"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|
|
@ -61,11 +61,10 @@ add-apt-repository "${REPO_NAME}"
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION libc++abi-dev libunwind-dev valgrind
|
apt-get install -y clang-$LLVM_VERSION lldb-$LLVM_VERSION lld-$LLVM_VERSION clangd-$LLVM_VERSION libc++abi-dev libunwind-dev valgrind
|
||||||
|
|
||||||
# install zig
|
# install zig - can't use apt-get since we require at least a specific commit later then the most recent tag (0.6.0)
|
||||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61
|
wget -c https://ziglang.org/builds/zig-linux-x86_64-0.6.0+0088efc4b.tar.xz --no-check-certificate
|
||||||
echo 'deb https://dl.bintray.com/dryzig/zig-ubuntu bionic main' | tee -a /etc/apt/sources.list
|
tar -xf zig-linux-x86_64-0.6.0+0088efc4b.tar.xz
|
||||||
apt update
|
ln -s "$PWD/zig-linux-x86_64-0.6.0+0088efc4b/zig" /usr/local/bin/zig
|
||||||
apt install zig
|
|
||||||
|
|
||||||
# symlink llvm tools
|
# symlink llvm tools
|
||||||
ln -s /usr/bin/llvm-as-10 /usr/local/bin/llvm-as
|
ln -s /usr/bin/llvm-as-10 /usr/local/bin/llvm-as
|
||||||
|
|
|
@ -89,4 +89,5 @@ quickcheck_macros = "0.8"
|
||||||
strip-ansi-escapes = "0.1"
|
strip-ansi-escapes = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde-xml-rs = "0.4"
|
serde-xml-rs = "0.4"
|
||||||
|
serial_test = "0.5"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
|
@ -12,123 +12,174 @@ mod helpers;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod cli_run {
|
mod cli_run {
|
||||||
use crate::helpers::{
|
use crate::helpers::{
|
||||||
example_file, extract_valgrind_errors, run_cmd, run_roc, run_with_valgrind, Out,
|
example_file, extract_valgrind_errors, run_cmd, run_roc, run_with_valgrind,
|
||||||
};
|
};
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
#[test]
|
fn check_output(
|
||||||
fn run_hello_world() {
|
folder: &str,
|
||||||
fn check_hello_world_output(out: Out) {
|
file: &str,
|
||||||
if !out.stderr.is_empty() {
|
flags: &[&str],
|
||||||
panic!(out.stderr);
|
expected_ending: &str,
|
||||||
}
|
use_valgrind: bool,
|
||||||
assert!(out.status.success());
|
) {
|
||||||
|
let compile_out = run_roc(
|
||||||
let (valgrind_out, raw_xml) =
|
&[
|
||||||
run_with_valgrind(&[example_file("hello-world", "app").to_str().unwrap()]);
|
&["build", example_file(folder, file).to_str().unwrap()],
|
||||||
|
flags,
|
||||||
let ending = "Hello, World!!!!!!!!!!!!!\n";
|
]
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
.concat(),
|
||||||
panic!(
|
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
|
||||||
ending, &valgrind_out.stdout
|
|
||||||
);
|
);
|
||||||
|
if !compile_out.stderr.is_empty() {
|
||||||
|
panic!(compile_out.stderr);
|
||||||
}
|
}
|
||||||
|
assert!(compile_out.status.success());
|
||||||
|
|
||||||
|
let out = if use_valgrind {
|
||||||
|
let (valgrind_out, raw_xml) =
|
||||||
|
run_with_valgrind(&[example_file(folder, "app").to_str().unwrap()]);
|
||||||
let memory_errors = extract_valgrind_errors(&raw_xml);
|
let memory_errors = extract_valgrind_errors(&raw_xml);
|
||||||
if !memory_errors.is_empty() {
|
if !memory_errors.is_empty() {
|
||||||
panic!("{:?}", memory_errors);
|
panic!("{:?}", memory_errors);
|
||||||
}
|
}
|
||||||
assert!(valgrind_out.status.success());
|
valgrind_out
|
||||||
|
} else {
|
||||||
|
run_cmd(example_file(folder, "app").to_str().unwrap(), &[])
|
||||||
|
};
|
||||||
|
if !&out.stdout.ends_with(expected_ending) {
|
||||||
|
panic!(
|
||||||
|
"expected output to end with {:?} but instead got {:#?}",
|
||||||
|
expected_ending, out
|
||||||
|
);
|
||||||
}
|
}
|
||||||
check_hello_world_output(run_roc(&[
|
assert!(out.status.success());
|
||||||
"build",
|
|
||||||
example_file("hello-world", "Hello.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
check_hello_world_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
"--optimize",
|
|
||||||
example_file("hello-world", "Hello.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial(hello_world)]
|
||||||
|
fn run_hello_world() {
|
||||||
|
check_output(
|
||||||
|
"hello-world",
|
||||||
|
"Hello.roc",
|
||||||
|
&[],
|
||||||
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(hello_world)]
|
||||||
|
fn run_hello_world_optimized() {
|
||||||
|
check_output(
|
||||||
|
"hello-world",
|
||||||
|
"Hello.roc",
|
||||||
|
&[],
|
||||||
|
"Hello, World!!!!!!!!!!!!!\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(quicksort)]
|
||||||
fn run_quicksort() {
|
fn run_quicksort() {
|
||||||
fn check_quicksort_output(out: Out) {
|
check_output(
|
||||||
if !out.stderr.is_empty() {
|
"quicksort",
|
||||||
panic!(out.stderr);
|
"Quicksort.roc",
|
||||||
}
|
&[],
|
||||||
assert!(out.status.success());
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
// let (valgrind_out, raw_xml) =
|
|
||||||
// run_with_valgrind(&[example_file("quicksort", "app").to_str().unwrap()]);
|
|
||||||
let valgrind_out = run_cmd(example_file("quicksort", "app").to_str().unwrap(), &[]);
|
|
||||||
let ending = "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n";
|
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
|
||||||
panic!(
|
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
|
||||||
ending, &valgrind_out.stdout
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// let memory_errors = extract_valgrind_errors(&raw_xml);
|
|
||||||
// if !memory_errors.is_empty() {
|
|
||||||
// panic!("{:?}", memory_errors);
|
|
||||||
// }
|
|
||||||
assert!(valgrind_out.status.success());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Uncomment this once we are correctly freeing the RocList even when in dev build.
|
|
||||||
/*
|
|
||||||
check_quicksort_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
*/
|
|
||||||
check_quicksort_output(run_roc(&[
|
|
||||||
"build",
|
|
||||||
"--optimize",
|
|
||||||
example_file("quicksort", "Quicksort.roc").to_str().unwrap(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn run_multi_module() {
|
#[serial(quicksort)]
|
||||||
fn check_muti_module_output(out: Out) {
|
fn run_quicksort_optimized() {
|
||||||
if !out.stderr.is_empty() {
|
check_output(
|
||||||
panic!(out.stderr);
|
"quicksort",
|
||||||
}
|
"Quicksort.roc",
|
||||||
assert!(out.status.success());
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
// let (valgrind_out, raw_xml) =
|
false,
|
||||||
// run_with_valgrind(&[example_file("multi-module", "app").to_str().unwrap()]);
|
|
||||||
let valgrind_out = run_cmd(example_file("multi-module", "app").to_str().unwrap(), &[]);
|
|
||||||
let ending = "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n";
|
|
||||||
if !&valgrind_out.stdout.ends_with(ending) {
|
|
||||||
panic!(
|
|
||||||
"expected output to end with {:?} but instead got {:?}",
|
|
||||||
ending, &valgrind_out.stdout
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// let memory_errors = extract_valgrind_errors(&raw_xml);
|
|
||||||
// if !memory_errors.is_empty() {
|
#[test]
|
||||||
// panic!("{:?}", memory_errors);
|
#[serial(quicksort)]
|
||||||
// }
|
// TODO: Stop ignoring this test once we are correctly freeing the RocList even when in dev build.
|
||||||
assert!(valgrind_out.status.success());
|
#[ignore]
|
||||||
|
fn run_quicksort_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"quicksort",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&[],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Uncomment this once we are correctly freeing the RocList even when in dev build.
|
#[test]
|
||||||
/*
|
#[serial(quicksort)]
|
||||||
check_muti_module_output(run_roc(&[
|
// TODO: Stop ignoring this test once valgrind supports AVX512.
|
||||||
"run",
|
#[ignore]
|
||||||
example_file("multi-module", "Quicksort.roc")
|
fn run_quicksort_optimized_valgrind() {
|
||||||
.to_str()
|
check_output(
|
||||||
.unwrap(),
|
"quicksort",
|
||||||
]));
|
"Quicksort.roc",
|
||||||
*/
|
&["--optimize"],
|
||||||
check_muti_module_output(run_roc(&[
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
"run",
|
true,
|
||||||
example_file("multi-module", "Quicksort.roc")
|
);
|
||||||
.to_str()
|
}
|
||||||
.unwrap(),
|
|
||||||
"--optimize",
|
#[test]
|
||||||
]));
|
#[serial(multi_module)]
|
||||||
|
fn run_multi_module() {
|
||||||
|
check_output(
|
||||||
|
"multi-module",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&[],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(multi_module)]
|
||||||
|
fn run_multi_module_optimized() {
|
||||||
|
check_output(
|
||||||
|
"multi-module",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(multi_module)]
|
||||||
|
// TODO: Stop ignoring this test once we are correctly freeing the RocList even when in dev build.
|
||||||
|
#[ignore]
|
||||||
|
fn run_multi_module_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"multi-module",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&[],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial(multi_module)]
|
||||||
|
// TODO: Stop ignoring this test once valgrind supports AVX512.
|
||||||
|
#[ignore]
|
||||||
|
fn run_multi_module_optimized_valgrind() {
|
||||||
|
check_output(
|
||||||
|
"multi-module",
|
||||||
|
"Quicksort.roc",
|
||||||
|
&["--optimize"],
|
||||||
|
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use std::path::PathBuf;
|
||||||
use std::process::{Command, ExitStatus, Stdio};
|
use std::process::{Command, ExitStatus, Stdio};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Out {
|
pub struct Out {
|
||||||
pub stdout: String,
|
pub stdout: String,
|
||||||
pub stderr: String,
|
pub stderr: String,
|
||||||
|
@ -131,6 +132,9 @@ enum ValgrindField {
|
||||||
Args(ValgrindDummyStruct),
|
Args(ValgrindDummyStruct),
|
||||||
Error(ValgrindError),
|
Error(ValgrindError),
|
||||||
Status(ValgrindDummyStruct),
|
Status(ValgrindDummyStruct),
|
||||||
|
Stack(ValgrindDummyStruct),
|
||||||
|
#[serde(rename = "fatal_signal")]
|
||||||
|
FatalSignal(ValgrindDummyStruct),
|
||||||
ErrorCounts(ValgrindDummyStruct),
|
ErrorCounts(ValgrindDummyStruct),
|
||||||
SuppCounts(ValgrindDummyStruct),
|
SuppCounts(ValgrindDummyStruct),
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub fn target_machine(
|
||||||
Target::from_name(arch).unwrap().create_target_machine(
|
Target::from_name(arch).unwrap().create_target_machine(
|
||||||
&TargetTriple::create(target_triple_str(target)),
|
&TargetTriple::create(target_triple_str(target)),
|
||||||
arch,
|
arch,
|
||||||
"+avx2", // TODO this string was used uncritically from an example, and should be reexamined
|
"", // TODO: this probably should be TargetMachine::get_host_cpu_features() to enable all features.
|
||||||
opt,
|
opt,
|
||||||
reloc,
|
reloc,
|
||||||
model,
|
model,
|
||||||
|
|
4
compiler/builtins/bitcode/.gitignore
vendored
4
compiler/builtins/bitcode/.gitignore
vendored
|
@ -1,4 +1,2 @@
|
||||||
main.ll
|
|
||||||
main.o
|
|
||||||
src/zig-cache
|
|
||||||
zig-cache
|
zig-cache
|
||||||
|
src/zig-cache
|
||||||
|
|
|
@ -5,31 +5,19 @@ When their implementations are simple enough (e.g. addition), they
|
||||||
can be implemented directly in Inkwell.
|
can be implemented directly in Inkwell.
|
||||||
|
|
||||||
When their implementations are complex enough, it's nicer to
|
When their implementations are complex enough, it's nicer to
|
||||||
implement them in a higher-level language like C (or eventually Zig),
|
implement them in a higher-level language like Zig, then compile
|
||||||
compile the result to LLVM bitcode, and import that bitcode into the compiler.
|
the result to LLVM bitcode, and import that bitcode into the compiler.
|
||||||
|
|
||||||
Compiling the bitcode happens automatically in a Rust build script at `compiler/gen/build.rs`.
|
Compiling the bitcode happens automatically in a Rust build script at `compiler/builtins/build.rs`.
|
||||||
You can find the compiled bitcode in `target/debug/build/roc_gen-[some random characters]/out/builtins.bc`.
|
Then `builtins/src/bitcode/rs` staticlly imports the compiled bitcode for use in the compiler.
|
||||||
|
|
||||||
> If you want to take a look at the human-readable LLVM IR, cd into `compiler/builtins/bitcode` and
|
You can find the compiled bitcode in `target/debug/build/roc_builtins-[some random characters]/out/builtins.bc`.
|
||||||
> run the following command. It should create `compiler/builtins/bitcode/lib.ll`
|
There will be two directories like `roc_builtins-[some random characters]`, look for the one that has an
|
||||||
>
|
`out` directory as a child.
|
||||||
> ```bash
|
|
||||||
> zig build-obj src/main.zig -femit-llvm-ir=test.ll -fno-emit-bin --strip
|
|
||||||
> ```
|
|
||||||
>
|
|
||||||
> NOTE: The full command that we use when generating the bitcode is:
|
|
||||||
> ```bash
|
|
||||||
> zig build-obj src/main.zig -femit-llvm-ir=test.ll -fno-emit-bin --strip -O ReleaseSafe
|
|
||||||
> ```
|
|
||||||
> This is probably less readable then the first command, because it does some mangling of
|
|
||||||
> non-exported names, etc. But if you're hitting a bug, it may be helpful.
|
|
||||||
|
|
||||||
The bitcode is a bunch of bytes that aren't particularly human-readable.
|
> 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
|
> If you want to take a look at the human-readable LLVM IR, look at
|
||||||
need to be included in the raw source somewhere.
|
> `target/debug/build/roc_builtins-[some random characters]/out/builtins.ll`
|
||||||
|
|
||||||
The `llvm/src/build.rs` file statically imports these raw bytes.
|
|
||||||
|
|
||||||
## Calling bitcode functions
|
## Calling bitcode functions
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const math = std.math;
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
const print = std.debug.print;
|
|
||||||
|
|
||||||
export fn is_finite_(f: f64) bool {
|
export fn atan_(num: f64) f64 {
|
||||||
return std.math.isFinite(f);
|
return math.atan(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn atan_(f: f64) f64 {
|
export fn is_finite_(num: f64) bool {
|
||||||
return std.math.atan(f);
|
return math.isFinite(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn pow_int_(base: i64, exp: i64) i64 {
|
export fn pow_int_(base: i64, exp: i64) i64 {
|
||||||
return std.math.pow(i64, base, exp);
|
return math.pow(i64, base, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Str.split
|
||||||
|
|
||||||
const RocStr = struct {
|
const RocStr = struct {
|
||||||
str_bytes: [*]u8,
|
str_bytes: [*]u8,
|
||||||
str_len: usize,
|
str_len: usize,
|
||||||
|
|
70
compiler/builtins/build.rs
Normal file
70
compiler/builtins/build.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use std::convert::AsRef;
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
fn run_command<S, I>(command: &str, args: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
let output_result = Command::new(OsStr::new(&command)).args(args).output();
|
||||||
|
match output_result {
|
||||||
|
Ok(output) => match output.status.success() {
|
||||||
|
true => (),
|
||||||
|
false => {
|
||||||
|
let error_str = match str::from_utf8(&output.stderr) {
|
||||||
|
Ok(stderr) => stderr.to_string(),
|
||||||
|
Err(_) => format!("Failed to run \"{}\"", command),
|
||||||
|
};
|
||||||
|
panic!("{} failed: {}", command, error_str);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(reason) => panic!("{} failed: {}", command, reason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
// "." is relative to where "build.rs" is
|
||||||
|
let src_path = Path::new(".").join("bitcode").join("src").join("main.zig");
|
||||||
|
let src_path_str = src_path.to_str().expect("Invalid src path");
|
||||||
|
println!("Building main.zig from: {}", src_path_str);
|
||||||
|
|
||||||
|
let zig_cache_dir = Path::new(&out_dir).join("zig-cache");
|
||||||
|
let zig_cache_dir_str = zig_cache_dir.to_str().expect("Invalid zig cache dir");
|
||||||
|
println!("Setting zig cache to: {}", zig_cache_dir_str);
|
||||||
|
|
||||||
|
let dest_ll_path = Path::new(&out_dir).join("builtins.ll");
|
||||||
|
let dest_ll = dest_ll_path.to_str().expect("Invalid dest ir path");
|
||||||
|
let emit_ir_arg = "-femit-llvm-ir=".to_owned() + dest_ll;
|
||||||
|
println!("Compiling zig llvm-ir to: {}", dest_ll);
|
||||||
|
|
||||||
|
run_command(
|
||||||
|
"zig",
|
||||||
|
&[
|
||||||
|
"build-obj",
|
||||||
|
src_path_str,
|
||||||
|
&emit_ir_arg,
|
||||||
|
"-fno-emit-bin",
|
||||||
|
"--strip",
|
||||||
|
"-O",
|
||||||
|
"ReleaseFast",
|
||||||
|
"--cache-dir",
|
||||||
|
zig_cache_dir_str,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let dest_bc_path = Path::new(&out_dir).join("builtins.bc");
|
||||||
|
let dest_bc = dest_bc_path.to_str().expect("Invalid dest bc path");
|
||||||
|
println!("Compiling bitcode to: {}", dest_bc);
|
||||||
|
|
||||||
|
run_command("llvm-as", &[dest_ll, "-o", dest_bc]);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed={}", src_path_str);
|
||||||
|
println!("cargo:rustc-env=BUILTINS_BC={}", dest_bc);
|
||||||
|
}
|
18
compiler/builtins/src/bitcode.rs
Normal file
18
compiler/builtins/src/bitcode.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::Read;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub fn get_bytes() -> Vec<u8> {
|
||||||
|
// In the build script for the builtins module, we compile the builtins bitcode and set
|
||||||
|
// BUILTINS_BC to the path to the compiled output.
|
||||||
|
let path: &'static str = env!(
|
||||||
|
"BUILTINS_BC",
|
||||||
|
"Env var BUILTINS_BC not found. Is there a problem with the build script?"
|
||||||
|
);
|
||||||
|
let mut builtins_bitcode = File::open(path).expect("Unable to find builtins bitcode source");
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
builtins_bitcode
|
||||||
|
.read_to_end(&mut buffer)
|
||||||
|
.expect("Unable to read builtins bitcode");
|
||||||
|
buffer
|
||||||
|
}
|
|
@ -10,5 +10,6 @@
|
||||||
// and encouraging shortcuts here creates bad incentives. I would rather temporarily
|
// and encouraging shortcuts here creates bad incentives. I would rather temporarily
|
||||||
// re-enable this when working on performance optimizations than have it block PRs.
|
// re-enable this when working on performance optimizations than have it block PRs.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
pub mod bitcode;
|
||||||
pub mod std;
|
pub mod std;
|
||||||
pub mod unique;
|
pub mod unique;
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let src_path = fs::canonicalize("./../builtins/bitcode/src/main.zig")
|
|
||||||
.expect("Failed to resolve bitcode source");
|
|
||||||
let src = src_path.to_str().expect("Invalid src path");
|
|
||||||
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
||||||
|
|
||||||
let dest_ll_path = Path::new(&out_dir).join("builtins.ll");
|
|
||||||
let dest_ll = dest_ll_path.to_str().expect("Invalid dest ir path");
|
|
||||||
let emit_ir_arg = "-femit-llvm-ir=".to_owned() + dest_ll;
|
|
||||||
Command::new("zig")
|
|
||||||
.args(&["build-obj", src, &emit_ir_arg, "-fno-emit-bin", "--strip", "-O", "ReleaseFast"])
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let dest_bc_path = Path::new(&out_dir).join("builtins.bc");
|
|
||||||
let dest_bc = dest_bc_path.to_str().expect("Invalid dest bc path");
|
|
||||||
Command::new("llvm-as")
|
|
||||||
.args(&[dest_ll, "-o", dest_bc])
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
|
||||||
println!("cargo:rerun-if-changed={}", src);
|
|
||||||
println!("cargo:rustc-env=BUILTINS_BC={}", dest_bc);
|
|
||||||
}
|
|
|
@ -29,13 +29,12 @@ use inkwell::values::{
|
||||||
};
|
};
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::{AddressSpace, IntPredicate};
|
use inkwell::{AddressSpace, IntPredicate};
|
||||||
|
use roc_builtins::bitcode;
|
||||||
use roc_collections::all::{ImMap, MutSet};
|
use roc_collections::all::{ImMap, MutSet};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use roc_mono::ir::{JoinPointId, Wrapped};
|
use roc_mono::ir::{JoinPointId, Wrapped};
|
||||||
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
use roc_mono::layout::{Builtin, Layout, MemoryMode};
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::Read;
|
|
||||||
use target_lexicon::CallingConvention;
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
@ -183,19 +182,9 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
||||||
// In the build script for the gen module, we compile the builtins bitcode and set
|
let bitcode_bytes = bitcode::get_bytes();
|
||||||
// BUILTINS_BC to the path to the compiled output.
|
|
||||||
let path: &'static str = env!(
|
|
||||||
"BUILTINS_BC",
|
|
||||||
"Env var BUILTINS_BC not found. Is there a problem with the build script?"
|
|
||||||
);
|
|
||||||
let mut builtins_bitcode = File::open(path).expect("Unable to find builtins bitcode source");
|
|
||||||
let mut buffer = std::vec::Vec::new();
|
|
||||||
builtins_bitcode
|
|
||||||
.read_to_end(&mut buffer)
|
|
||||||
.expect("Unable to read builtins bitcode");
|
|
||||||
|
|
||||||
let memory_buffer = MemoryBuffer::create_from_memory_range(&buffer, module_name);
|
let memory_buffer = MemoryBuffer::create_from_memory_range(&bitcode_bytes, module_name);
|
||||||
|
|
||||||
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||||
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
||||||
|
|
31
nix/zig.nix
31
nix/zig.nix
|
@ -1,21 +1,28 @@
|
||||||
{ pkgs, isMacOS }:
|
{ pkgs, isMacOS }:
|
||||||
|
|
||||||
if isMacOS
|
# We require at least specific commit of Zig after the latest tagged
|
||||||
then
|
# release (0.6.0), so we just download the binaries for that commit
|
||||||
# As of 2020-10-25, building Zig from source on MacOS fails
|
|
||||||
# so we just download the binary from their release page
|
let
|
||||||
let
|
version = "0.6.0+0088efc4b";
|
||||||
version = "0.6.0";
|
osName =
|
||||||
archiveName = "zig-macos-x86_64-${version}+91a1c20e7";
|
if isMacOS
|
||||||
in
|
then "macos"
|
||||||
pkgs.stdenv.mkDerivation {
|
else "linux";
|
||||||
|
archiveName = "zig-${osName}-x86_64-${version}";
|
||||||
|
sha256 =
|
||||||
|
if isMacOS
|
||||||
|
then "665c1a7f472cfc5e0715f0ddf6ff8409fb749ac91cbbae68c443b4a37ebd058e"
|
||||||
|
else "bab70ae3bd0af538022bc3ef50d8f34fa8dceac39ba7d9e5d528eee7e6d5a1cf";
|
||||||
|
in
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
pname = "zig";
|
pname = "zig";
|
||||||
version = version;
|
version = version;
|
||||||
buildInputs = [ pkgs.gzip ];
|
buildInputs = [ pkgs.gzip ];
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl {
|
||||||
|
inherit sha256;
|
||||||
name = "${archiveName}.tar.xz";
|
name = "${archiveName}.tar.xz";
|
||||||
url = "https://ziglang.org/builds/${archiveName}.tar.xz";
|
url = "https://ziglang.org/builds/${archiveName}.tar.xz";
|
||||||
sha256 = "0svwlk76w171ikr8wjzchm4svd4hvna8idv84pi7ar2fr4i8bkic";
|
|
||||||
};
|
};
|
||||||
phases = [ "installPhase" ];
|
phases = [ "installPhase" ];
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
|
@ -26,6 +33,4 @@ if isMacOS
|
||||||
ln -s "$out/zig" "$out/bin/zig"
|
ln -s "$out/zig" "$out/bin/zig"
|
||||||
chmod +x $out/bin/zig
|
chmod +x $out/bin/zig
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
else
|
|
||||||
pkgs.zig
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
{ pkgs, zig }:
|
{ pkgs, zig }:
|
||||||
|
|
||||||
# As of 2020-10-25, building zls is not available on Nix
|
# As of 2020-10-25, building zls is not available on Nix. For some reason,
|
||||||
# For some reason, this hangs on `zig build`. I'll try
|
# this hangs on `zig build`. I'll try to figure it our later.
|
||||||
# to figure it our later :(
|
|
||||||
|
|
||||||
let
|
let
|
||||||
rev = "e8c20351d85da8eb4bf22480045b994007284d69";
|
rev = "e8c20351d85da8eb4bf22480045b994007284d69";
|
||||||
|
|
|
@ -35,9 +35,9 @@ let
|
||||||
# build libraries
|
# build libraries
|
||||||
pkgs.rustup
|
pkgs.rustup
|
||||||
pkgs.cargo
|
pkgs.cargo
|
||||||
|
llvm
|
||||||
pkgs.valgrind
|
pkgs.valgrind
|
||||||
zig
|
zig
|
||||||
llvm
|
|
||||||
# llb deps
|
# llb deps
|
||||||
pkgs.libffi
|
pkgs.libffi
|
||||||
pkgs.libxml2
|
pkgs.libxml2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue