Merge pull request #2268 from rtfeldman/update_zig_09

Update to Zig 0.9 + LLVM 13
This commit is contained in:
Folkert de Vries 2022-05-08 23:29:45 +02:00 committed by GitHub
commit 5d3b83f5a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 1037 additions and 555 deletions

View file

@ -126,7 +126,7 @@ sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
``` ```
### Zig ### Zig
**version: 0.8.0** **version: 0.9.1**
For any OS, you can use [`zigup`](https://github.com/marler8997/zigup) to manage zig installations. For any OS, you can use [`zigup`](https://github.com/marler8997/zigup) to manage zig installations.
@ -138,14 +138,14 @@ If you prefer a package manager, you can try the following:
If you want to install it manually, you can also download Zig directly [here](https://ziglang.org/download/). Just make sure you download the right version, the bleeding edge master build is the first download link on this page. If you want to install it manually, you can also download Zig directly [here](https://ziglang.org/download/). Just make sure you download the right version, the bleeding edge master build is the first download link on this page.
### LLVM ### LLVM
**version: 12.0.x** **version: 13.0.x**
For macOS, you can install LLVM 12 using `brew install llvm@12` and then adding For macOS, you can install LLVM 13 using `brew install llvm@13` and then adding
`$(brew --prefix llvm@12)/bin` to your `PATH`. You can confirm this worked by `$(brew --prefix llvm@13)/bin` to your `PATH`. You can confirm this worked by
running `llc --version` - it should mention "LLVM version 12.0.0" at the top. running `llc --version` - it should mention "LLVM version 13.0.0" at the top.
You may also need to manually specify a prefix env var like so: You may also need to manually specify a prefix env var like so:
``` ```
export LLVM_SYS_120_PREFIX=/usr/local/opt/llvm@12 export LLVM_SYS_130_PREFIX=/usr/local/opt/llvm@13
``` ```
For Ubuntu and Debian: For Ubuntu and Debian:
@ -153,19 +153,15 @@ For Ubuntu and Debian:
sudo apt -y install lsb-release software-properties-common gnupg sudo apt -y install lsb-release software-properties-common gnupg
wget https://apt.llvm.org/llvm.sh wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh chmod +x llvm.sh
./llvm.sh 12 ./llvm.sh 13
``` ```
If you use this script, you'll need to add `clang` and `llvm-as` to your `PATH`. If you use this script, you'll need to add `clang` to your `PATH`.
By default, the script installs them as `clang-12` and `llvm-as-12`, By default, the script installs it as `clang-13`. You can address this with symlinks like so:
respectively. You can address this with symlinks like so:
``` ```
sudo ln -s /usr/bin/clang-12 /usr/bin/clang sudo ln -s /usr/bin/clang-13 /usr/bin/clang
``` ```
```
sudo ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as
````
There are also alternative installation options at http://releases.llvm.org/download.html There are also alternative installation options at http://releases.llvm.org/download.html

4
Cargo.lock generated
View file

@ -2071,9 +2071,9 @@ checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "120.2.4" version = "130.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09b716322964966a62377cf86e64f00ca7043505fdf27bd2ec7d41ae6682d1e7" checksum = "95eb03b4f7ae21f48ef7c565a3e3aa22c50616aea64645fb1fd7f6f56b51c274"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",

View file

@ -17,9 +17,9 @@ install-zig-llvm-valgrind-clippy-rustfmt:
# editor # editor
RUN apt -y install libxkbcommon-dev RUN apt -y install libxkbcommon-dev
# zig # zig
RUN wget -c https://ziglang.org/download/0.8.0/zig-linux-x86_64-0.8.0.tar.xz --no-check-certificate RUN wget -c https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz --no-check-certificate
RUN tar -xf zig-linux-x86_64-0.8.0.tar.xz RUN tar -xf zig-linux-x86_64-0.9.1.tar.xz
RUN ln -s /earthbuild/zig-linux-x86_64-0.8.0/zig /bin/zig RUN ln -s /earthbuild/zig-linux-x86_64-0.9.1/zig /bin/zig
# zig builtins wasm tests # zig builtins wasm tests
RUN apt -y install build-essential RUN apt -y install build-essential
RUN cargo install wasmer-cli --features "singlepass" RUN cargo install wasmer-cli --features "singlepass"
@ -27,11 +27,10 @@ install-zig-llvm-valgrind-clippy-rustfmt:
RUN apt -y install lsb-release software-properties-common gnupg RUN apt -y install lsb-release software-properties-common gnupg
RUN wget https://apt.llvm.org/llvm.sh RUN wget https://apt.llvm.org/llvm.sh
RUN chmod +x llvm.sh RUN chmod +x llvm.sh
RUN ./llvm.sh 12 RUN ./llvm.sh 13
RUN ln -s /usr/bin/clang-12 /usr/bin/clang RUN ln -s /usr/bin/clang-13 /usr/bin/clang
RUN ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as
# use lld as linker # use lld as linker
RUN ln -s /usr/bin/lld-12 /usr/bin/ld.lld RUN ln -s /usr/bin/lld-13 /usr/bin/ld.lld
ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld -C target-cpu=native" ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld -C target-cpu=native"
# valgrind # valgrind
RUN apt -y install valgrind RUN apt -y install valgrind

View file

@ -76,9 +76,9 @@ popd
valgrind --version valgrind --version
# install zig - can't use apt-get since we require at least a specific commit later then the most recent tag (0.6.0) # install zig - can't use apt-get since we require at least a specific commit later then the most recent tag (0.6.0)
wget -c https://ziglang.org/download/0.7.1/zig-linux-x86_64-0.7.1.tar.xz --no-check-certificate wget -c https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz --no-check-certificate
tar -xf zig-linux-x86_64-0.7.1.tar.xz tar -xf zig-linux-x86_64-0.9.1.tar.xz
ln -s "$PWD/zig-linux-x86_64-0.7.1/zig" /usr/local/bin/zig ln -s "$PWD/zig-linux-x86_64-0.9.1/zig" /usr/local/bin/zig
# test sccache # test sccache
./ci/sccache -V ./ci/sccache -V

View file

@ -756,7 +756,7 @@ mod cli_run {
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending: "", expected_ending: "",
use_valgrind: true, use_valgrind: false,
}, },
issue2279 => Example { issue2279 => Example {
filename: "Issue2279.roc", filename: "Issue2279.roc",

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const str = @import("str"); const str = @import("str");
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
@ -14,7 +15,7 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -22,23 +23,28 @@ comptime {
const mem = std.mem; const mem = std.mem;
const Allocator = mem.Allocator; const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed() RocStr; extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
extern fn malloc(size: usize) callconv(.C) ?*c_void; const Align = 2 * @alignOf(usize);
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
_ = alignment;
return malloc(size); return malloc(size);
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
_ = old_size;
_ = alignment;
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
_ = alignment;
free(@alignCast(16, @ptrCast([*]u8, c_ptr))); free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
} }
@ -50,7 +56,9 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
return memset(dst, value, size); return memset(dst, value, size);
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
const msg = @ptrCast([*:0]const u8, c_ptr); const msg = @ptrCast([*:0]const u8, c_ptr);
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
@ -65,14 +73,15 @@ pub export fn main() i32 {
// start time // start time
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
// actually call roc to populate the callresult // actually call roc to populate the callresult
const callresult = roc__mainForHost_1_exposed(); var callresult = RocStr.empty();
roc__mainForHost_1_exposed_generic(&callresult);
// end time // end time
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
// stdout the result // stdout the result
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable; stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const str = @import("str"); const str = @import("str");
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
@ -14,7 +15,7 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -22,23 +23,27 @@ comptime {
const mem = std.mem; const mem = std.mem;
const Allocator = mem.Allocator; const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed() RocStr; extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
extern fn malloc(size: usize) callconv(.C) ?*c_void; extern fn malloc(size: usize) callconv(.C) ?*anyopaque;
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
_ = alignment;
return malloc(size); return malloc(size);
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
_ = old_size;
_ = alignment;
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
_ = alignment;
free(@alignCast(16, @ptrCast([*]u8, c_ptr))); free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
} }
@ -50,7 +55,9 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
return memset(dst, value, size); return memset(dst, value, size);
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
const msg = @ptrCast([*:0]const u8, c_ptr); const msg = @ptrCast([*:0]const u8, c_ptr);
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
@ -65,14 +72,15 @@ pub export fn main() i32 {
// start time // start time
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
// actually call roc to populate the callresult // actually call roc to populate the callresult
const callresult = roc__mainForHost_1_exposed(); var callresult = RocStr.empty();
roc__mainForHost_1_exposed_generic(&callresult);
// end time // end time
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
// stdout the result // stdout the result
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable; stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;

332
cli_utils/Cargo.lock generated
View file

@ -124,9 +124,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
@ -188,10 +188,22 @@ version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
dependencies = [ dependencies = [
"funty", "funty 1.2.0",
"radium", "radium 0.6.2",
"tap", "tap",
"wyz", "wyz 0.4.0",
]
[[package]]
name = "bitvec"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b"
dependencies = [
"funty 2.0.0",
"radium 0.7.0",
"tap",
"wyz 0.5.0",
] ]
[[package]] [[package]]
@ -346,17 +358,26 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.0.0-beta.5" version = "3.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" checksum = "47582c09be7c8b32c0ab3a6181825ababb713fde6fff20fc573a3870dd45c6a0"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_lex",
"indexmap", "indexmap",
"os_str_bytes",
"strsim 0.10.0", "strsim 0.10.0",
"termcolor", "termcolor",
"textwrap 0.14.2", "textwrap 0.15.0",
]
[[package]]
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
] ]
[[package]] [[package]]
@ -958,7 +979,7 @@ checksum = "a16910e685088843d53132b04e0f10a571fdb193224fc589685b3ba1ce4cb03d"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"windows-sys", "windows-sys 0.28.0",
] ]
[[package]] [[package]]
@ -1015,6 +1036,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.17" version = "0.3.17"
@ -1297,7 +1324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f" checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"static_assertions", "static_assertions 1.1.0",
] ]
[[package]] [[package]]
@ -1348,26 +1375,26 @@ dependencies = [
name = "inkwell" name = "inkwell"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1)", "inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?branch=master)",
] ]
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1#e15d665227b2acad4ca949820d80048e09f3f4e5" source = "git+https://github.com/rtfeldman/inkwell?branch=master#accd406858a40ca2a1463ff77d79f3c5e4c96f4e"
dependencies = [ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
"libc", "libc",
"llvm-sys", "llvm-sys",
"once_cell", "once_cell",
"parking_lot", "parking_lot 0.12.0",
] ]
[[package]] [[package]]
name = "inkwell_internals" name = "inkwell_internals"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1#e15d665227b2acad4ca949820d80048e09f3f4e5" source = "git+https://github.com/rtfeldman/inkwell?branch=master#accd406858a40ca2a1463ff77d79f3c5e4c96f4e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1496,9 +1523,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "120.2.1" version = "130.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a810627ac62b396f5fd2214ba9bbd8748d4d6efdc4d2c1c1303ea7a75763ce" checksum = "95eb03b4f7ae21f48ef7c565a3e3aa22c50616aea64645fb1fd7f6f56b51c274"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
@ -1509,10 +1536,11 @@ dependencies = [
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.5" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [ dependencies = [
"autocfg",
"scopeguard", "scopeguard",
] ]
@ -1566,9 +1594,9 @@ dependencies = [
[[package]] [[package]]
name = "memmap2" name = "memmap2"
version = "0.5.0" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -1949,12 +1977,9 @@ dependencies = [
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "4.2.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "owned_ttf_parser" name = "owned_ttf_parser"
@ -1980,7 +2005,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c48e482b9a59ad6c2cdb06f7725e7bd33fe3525baaf4699fde7bfea6a5b77b1" checksum = "9c48e482b9a59ad6c2cdb06f7725e7bd33fe3525baaf4699fde7bfea6a5b77b1"
dependencies = [ dependencies = [
"bitvec", "bitvec 0.22.3",
"packed_struct_codegen", "packed_struct_codegen",
"serde", "serde",
] ]
@ -2038,7 +2063,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [ dependencies = [
"instant", "instant",
"lock_api", "lock_api",
"parking_lot_core", "parking_lot_core 0.8.5",
]
[[package]]
name = "parking_lot"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [
"lock_api",
"parking_lot_core 0.9.2",
] ]
[[package]] [[package]]
@ -2055,6 +2090,46 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "parking_lot_core"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"smallvec",
"windows-sys 0.34.0",
]
[[package]]
name = "peg"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af728fe826811af3b38c37e93de6d104485953ea373d656eebae53d6987fcd2c"
dependencies = [
"peg-macros",
"peg-runtime",
]
[[package]]
name = "peg-macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4536be147b770b824895cbad934fccce8e49f14b4c4946eaa46a6e4a12fcdc16"
dependencies = [
"peg-runtime",
"proc-macro2",
"quote",
]
[[package]]
name = "peg-runtime"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.1.0" version = "2.1.0"
@ -2280,6 +2355,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "radix_trie" name = "radix_trie"
version = "0.2.1" version = "0.2.1"
@ -2451,6 +2532,17 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "roc_alias_analysis"
version = "0.1.0"
dependencies = [
"morphic_lib",
"roc_collections",
"roc_debug_flags",
"roc_module",
"roc_mono",
]
[[package]] [[package]]
name = "roc_ast" name = "roc_ast"
version = "0.1.0" version = "0.1.0"
@ -2468,11 +2560,13 @@ dependencies = [
"roc_parse", "roc_parse",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_reporting",
"roc_target", "roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"snafu", "snafu",
"ven_graph", "ven_graph",
"winapi",
] ]
[[package]] [[package]]
@ -2486,6 +2580,7 @@ dependencies = [
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_constrain", "roc_constrain",
"roc_error_macros",
"roc_gen_dev", "roc_gen_dev",
"roc_gen_llvm", "roc_gen_llvm",
"roc_gen_wasm", "roc_gen_wasm",
@ -2504,6 +2599,7 @@ dependencies = [
"serde_json", "serde_json",
"target-lexicon", "target-lexicon",
"tempfile", "tempfile",
"wasi_libc_sys",
] ]
[[package]] [[package]]
@ -2511,6 +2607,7 @@ name = "roc_builtins"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dunce", "dunce",
"lazy_static",
"roc_collections", "roc_collections",
"roc_module", "roc_module",
"roc_region", "roc_region",
@ -2522,16 +2619,17 @@ dependencies = [
name = "roc_can" name = "roc_can"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitvec 1.0.0",
"bumpalo", "bumpalo",
"roc_builtins",
"roc_collections", "roc_collections",
"roc_error_macros", "roc_error_macros",
"roc_exhaustive",
"roc_module", "roc_module",
"roc_parse", "roc_parse",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_types", "roc_types",
"ven_graph", "static_assertions 1.1.0",
] ]
[[package]] [[package]]
@ -2539,7 +2637,7 @@ name = "roc_cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"clap 3.0.0-beta.5", "clap 3.1.17",
"const_format", "const_format",
"mimalloc", "mimalloc",
"roc_build", "roc_build",
@ -2592,6 +2690,7 @@ dependencies = [
name = "roc_constrain" name = "roc_constrain"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arrayvec 0.7.2",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
@ -2602,21 +2701,28 @@ dependencies = [
"roc_types", "roc_types",
] ]
[[package]]
name = "roc_debug_flags"
version = "0.1.0"
[[package]] [[package]]
name = "roc_docs" name = "roc_docs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"peg",
"pulldown-cmark", "pulldown-cmark",
"roc_ast", "roc_ast",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
"roc_code_markup", "roc_code_markup",
"roc_collections", "roc_collections",
"roc_highlight",
"roc_load", "roc_load",
"roc_module", "roc_module",
"roc_parse", "roc_parse",
"roc_region", "roc_region",
"roc_reporting",
"roc_target", "roc_target",
"roc_types", "roc_types",
"snafu", "snafu",
@ -2671,6 +2777,16 @@ dependencies = [
name = "roc_error_macros" name = "roc_error_macros"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "roc_exhaustive"
version = "0.1.0"
dependencies = [
"roc_collections",
"roc_module",
"roc_region",
"roc_std",
]
[[package]] [[package]]
name = "roc_fmt" name = "roc_fmt"
version = "0.1.0" version = "0.1.0"
@ -2696,7 +2812,6 @@ dependencies = [
"roc_mono", "roc_mono",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
"roc_reporting",
"roc_solve", "roc_solve",
"roc_target", "roc_target",
"roc_types", "roc_types",
@ -2711,8 +2826,10 @@ dependencies = [
"bumpalo", "bumpalo",
"inkwell 0.1.0", "inkwell 0.1.0",
"morphic_lib", "morphic_lib",
"roc_alias_analysis",
"roc_builtins", "roc_builtins",
"roc_collections", "roc_collections",
"roc_debug_flags",
"roc_error_macros", "roc_error_macros",
"roc_module", "roc_module",
"roc_mono", "roc_mono",
@ -2735,6 +2852,14 @@ dependencies = [
"roc_target", "roc_target",
] ]
[[package]]
name = "roc_highlight"
version = "0.1.0"
dependencies = [
"peg",
"roc_code_markup",
]
[[package]] [[package]]
name = "roc_ident" name = "roc_ident"
version = "0.1.0" version = "0.1.0"
@ -2745,9 +2870,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"bumpalo", "bumpalo",
"clap 3.0.0-beta.5", "clap 3.1.17",
"iced-x86", "iced-x86",
"memmap2 0.5.0", "memmap2 0.5.3",
"object 0.26.2", "object 0.26.2",
"roc_build", "roc_build",
"roc_collections", "roc_collections",
@ -2760,16 +2885,31 @@ dependencies = [
[[package]] [[package]]
name = "roc_load" name = "roc_load"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bumpalo",
"roc_builtins",
"roc_collections",
"roc_constrain",
"roc_load_internal",
"roc_module",
"roc_reporting",
"roc_target",
"roc_types",
]
[[package]]
name = "roc_load_internal"
version = "0.1.0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"crossbeam", "crossbeam",
"morphic_lib",
"num_cpus", "num_cpus",
"parking_lot", "parking_lot 0.12.0",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_constrain", "roc_constrain",
"roc_debug_flags",
"roc_error_macros", "roc_error_macros",
"roc_module", "roc_module",
"roc_mono", "roc_mono",
@ -2795,7 +2935,7 @@ dependencies = [
"roc_ident", "roc_ident",
"roc_region", "roc_region",
"snafu", "snafu",
"static_assertions", "static_assertions 1.1.0",
] ]
[[package]] [[package]]
@ -2804,11 +2944,12 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"hashbrown 0.11.2", "hashbrown 0.11.2",
"morphic_lib",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_debug_flags",
"roc_error_macros", "roc_error_macros",
"roc_exhaustive",
"roc_module", "roc_module",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
@ -2817,7 +2958,7 @@ dependencies = [
"roc_target", "roc_target",
"roc_types", "roc_types",
"roc_unify", "roc_unify",
"static_assertions", "static_assertions 1.1.0",
"ven_graph", "ven_graph",
"ven_pretty", "ven_pretty",
] ]
@ -2841,13 +2982,14 @@ dependencies = [
"roc_module", "roc_module",
"roc_parse", "roc_parse",
"roc_region", "roc_region",
"roc_types",
] ]
[[package]] [[package]]
name = "roc_region" name = "roc_region"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"static_assertions", "static_assertions 1.1.0",
] ]
[[package]] [[package]]
@ -2866,6 +3008,8 @@ dependencies = [
"roc_mono", "roc_mono",
"roc_parse", "roc_parse",
"roc_repl_eval", "roc_repl_eval",
"roc_reporting",
"roc_std",
"roc_target", "roc_target",
"roc_types", "roc_types",
"rustyline", "rustyline",
@ -2888,6 +3032,7 @@ dependencies = [
"roc_parse", "roc_parse",
"roc_region", "roc_region",
"roc_reporting", "roc_reporting",
"roc_std",
"roc_target", "roc_target",
"roc_types", "roc_types",
] ]
@ -2900,8 +3045,8 @@ dependencies = [
"distance", "distance",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_exhaustive",
"roc_module", "roc_module",
"roc_mono",
"roc_parse", "roc_parse",
"roc_problem", "roc_problem",
"roc_region", "roc_region",
@ -2918,6 +3063,9 @@ dependencies = [
"bumpalo", "bumpalo",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_debug_flags",
"roc_error_macros",
"roc_exhaustive",
"roc_module", "roc_module",
"roc_region", "roc_region",
"roc_types", "roc_types",
@ -2927,6 +3075,9 @@ dependencies = [
[[package]] [[package]]
name = "roc_std" name = "roc_std"
version = "0.1.0" version = "0.1.0"
dependencies = [
"static_assertions 0.1.1",
]
[[package]] [[package]]
name = "roc_target" name = "roc_target"
@ -2941,10 +3092,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"roc_collections", "roc_collections",
"roc_debug_flags",
"roc_error_macros", "roc_error_macros",
"roc_module", "roc_module",
"roc_region", "roc_region",
"static_assertions", "static_assertions 1.1.0",
"ven_ena", "ven_ena",
] ]
@ -2954,6 +3106,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"roc_collections", "roc_collections",
"roc_debug_flags",
"roc_error_macros",
"roc_module", "roc_module",
"roc_types", "roc_types",
] ]
@ -2999,7 +3153,7 @@ dependencies = [
[[package]] [[package]]
name = "rustyline" name = "rustyline"
version = "9.1.1" version = "9.1.1"
source = "git+https://github.com/rtfeldman/rustyline?tag=v9.1.1#7053ae0fe0ee710d38ed5845dd979113382994dc" source = "git+https://github.com/rtfeldman/rustyline?rev=e74333c#e74333c0d618896b88175bf06645108f996fe6d0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -3022,7 +3176,7 @@ dependencies = [
[[package]] [[package]]
name = "rustyline-derive" name = "rustyline-derive"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/rtfeldman/rustyline?tag=v9.1.1#7053ae0fe0ee710d38ed5845dd979113382994dc" source = "git+https://github.com/rtfeldman/rustyline?rev=e74333c#e74333c0d618896b88175bf06645108f996fe6d0"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn",
@ -3285,6 +3439,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "static_assertions"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f406d6ee68db6796e11ffd7b4d171864c58b7451e79ef9460ea33c287a1f89a7"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -3337,9 +3497,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.12.2" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff" checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
@ -3375,9 +3535,9 @@ dependencies = [
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.14.2" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
@ -3447,7 +3607,7 @@ checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"rand", "rand",
"static_assertions", "static_assertions 1.1.0",
] ]
[[package]] [[package]]
@ -3567,6 +3727,10 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi_libc_sys"
version = "0.1.0"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.79" version = "0.2.79"
@ -3798,7 +3962,7 @@ dependencies = [
"arrayvec 0.7.2", "arrayvec 0.7.2",
"js-sys", "js-sys",
"log", "log",
"parking_lot", "parking_lot 0.11.2",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec",
"wasm-bindgen", "wasm-bindgen",
@ -3822,7 +3986,7 @@ dependencies = [
"fxhash", "fxhash",
"log", "log",
"naga", "naga",
"parking_lot", "parking_lot 0.11.2",
"profiling", "profiling",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec",
@ -3857,7 +4021,7 @@ dependencies = [
"metal", "metal",
"naga", "naga",
"objc", "objc",
"parking_lot", "parking_lot 0.11.2",
"profiling", "profiling",
"range-alloc", "range-alloc",
"raw-window-handle", "raw-window-handle",
@ -3927,11 +4091,24 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
dependencies = [ dependencies = [
"windows_aarch64_msvc", "windows_aarch64_msvc 0.28.0",
"windows_i686_gnu", "windows_i686_gnu 0.28.0",
"windows_i686_msvc", "windows_i686_msvc 0.28.0",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.28.0",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.28.0",
]
[[package]]
name = "windows-sys"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825"
dependencies = [
"windows_aarch64_msvc 0.34.0",
"windows_i686_gnu 0.34.0",
"windows_i686_msvc 0.34.0",
"windows_x86_64_gnu 0.34.0",
"windows_x86_64_msvc 0.34.0",
] ]
[[package]] [[package]]
@ -3940,30 +4117,60 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
[[package]]
name = "windows_aarch64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.28.0" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
[[package]]
name = "windows_i686_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.28.0" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
[[package]]
name = "windows_i686_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.28.0" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
[[package]]
name = "windows_x86_64_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.28.0" version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
[[package]]
name = "windows_x86_64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.25.0" version = "0.25.0"
@ -3986,7 +4193,7 @@ dependencies = [
"ndk-glue", "ndk-glue",
"ndk-sys", "ndk-sys",
"objc", "objc",
"parking_lot", "parking_lot 0.11.2",
"percent-encoding", "percent-encoding",
"raw-window-handle", "raw-window-handle",
"scopeguard", "scopeguard",
@ -4014,6 +4221,15 @@ dependencies = [
"tap", "tap",
] ]
[[package]]
name = "wyz"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
dependencies = [
"tap",
]
[[package]] [[package]]
name = "x11-clipboard" name = "x11-clipboard"
version = "0.5.3" version = "0.5.3"

View file

@ -19,11 +19,6 @@ pub struct CodeGenTiming {
pub emit_o_file: Duration, pub emit_o_file: Duration,
} }
// TODO: If modules besides this one start needing to know which version of
// llvm we're using, consider moving me somewhere else.
#[cfg(feature = "llvm")]
const LLVM_VERSION: &str = "12";
pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Problems { pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Problems {
report_problems_help( report_problems_help(
loaded.total_problems(), loaded.total_problems(),
@ -357,9 +352,11 @@ pub fn gen_from_mono_module_llvm(
use target_lexicon::Architecture; use target_lexicon::Architecture;
match target.architecture { match target.architecture {
Architecture::X86_64 | Architecture::X86_32(_) | Architecture::Aarch64(_) => { Architecture::X86_64
// assemble the .ll into a .bc | Architecture::X86_32(_)
let _ = Command::new("llvm-as") | Architecture::Aarch64(_)
| Architecture::Wasm32 => {
let ll_to_bc = Command::new("llvm-as")
.args(&[ .args(&[
app_ll_dbg_file.to_str().unwrap(), app_ll_dbg_file.to_str().unwrap(),
"-o", "-o",
@ -368,6 +365,8 @@ pub fn gen_from_mono_module_llvm(
.output() .output()
.unwrap(); .unwrap();
assert!(ll_to_bc.stderr.is_empty(), "{:#?}", ll_to_bc);
let llc_args = &[ let llc_args = &[
"-relocation-model=pic", "-relocation-model=pic",
"-filetype=obj", "-filetype=obj",
@ -381,26 +380,9 @@ pub fn gen_from_mono_module_llvm(
// //
// different systems name this executable differently, so we shotgun for // different systems name this executable differently, so we shotgun for
// the most common ones and then give up. // the most common ones and then give up.
let _: Result<std::process::Output, std::io::Error> = let bc_to_object = Command::new("llc").args(llc_args).output().unwrap();
Command::new(format!("llc-{}", LLVM_VERSION))
.args(llc_args)
.output()
.or_else(|_| Command::new("llc").args(llc_args).output())
.map_err(|_| {
panic!("We couldn't find llc-{} on your machine!", LLVM_VERSION);
});
}
Architecture::Wasm32 => { assert!(bc_to_object.stderr.is_empty(), "{:#?}", bc_to_object);
// assemble the .ll into a .bc
let _ = Command::new("llvm-as")
.args(&[
app_ll_dbg_file.to_str().unwrap(),
"-o",
app_o_file.to_str().unwrap(),
])
.output()
.unwrap();
} }
_ => unreachable!(), _ => unreachable!(),
} }

View file

@ -5,7 +5,7 @@ const CrossTarget = std.zig.CrossTarget;
const Arch = std.Target.Cpu.Arch; const Arch = std.Target.Cpu.Arch;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
// b.setPreferredReleaseMode(builtin.Mode.Debug // b.setPreferredReleaseMode(.Debug);
b.setPreferredReleaseMode(.ReleaseFast); b.setPreferredReleaseMode(.ReleaseFast);
const mode = b.standardReleaseOptions(); const mode = b.standardReleaseOptions();
@ -57,8 +57,9 @@ fn generateLlvmIrFile(
const obj = b.addObject(object_name, main_path); const obj = b.addObject(object_name, main_path);
obj.setBuildMode(mode); obj.setBuildMode(mode);
obj.strip = true; obj.strip = true;
obj.emit_llvm_ir = true; obj.emit_llvm_ir = .emit;
obj.emit_bin = false; obj.emit_llvm_bc = .emit;
obj.emit_bin = .no_emit;
obj.target = target; obj.target = target;
const ir = b.step(step_name, "Build LLVM ir"); const ir = b.step(step_name, "Build LLVM ir");

View file

@ -4,6 +4,8 @@ set -euxo pipefail
# Test failures will always point at the _start function # Test failures will always point at the _start function
# Make sure to look at the rest of the stack trace! # Make sure to look at the rest of the stack trace!
warning_about_non_native_binary=$(zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig 2>&1)
wasm_test_binary=$(echo $warning_about_non_native_binary | cut -d' ' -f 3) # Zig will try to run the test binary it produced, but it is a wasm object and hence your OS won't
wasmer $wasm_test_binary dummyArgForZigTestBinary # know how to run it. In the error message, it prints the binary it tried to run. We use some fun
# unix tools to get that path, then feed it to wasmer
zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd wasmer --test-cmd-bin

View file

@ -139,7 +139,7 @@ pub const RocDec = extern struct {
// Format the backing i128 into an array of digit (ascii) characters (u8s) // Format the backing i128 into an array of digit (ascii) characters (u8s)
var digit_bytes_storage: [max_digits + 1]u8 = undefined; var digit_bytes_storage: [max_digits + 1]u8 = undefined;
var num_digits = std.fmt.formatIntBuf(digit_bytes_storage[0..], num, 10, false, .{}); var num_digits = std.fmt.formatIntBuf(digit_bytes_storage[0..], num, 10, .lower, .{});
var digit_bytes: [*]u8 = digit_bytes_storage[0..]; var digit_bytes: [*]u8 = digit_bytes_storage[0..];
// space where we assemble all the characters that make up the final string // space where we assemble all the characters that make up the final string

View file

@ -27,18 +27,8 @@ pub fn expectFailed(
// Lock the failures mutex before reading from any of the failures globals, // Lock the failures mutex before reading from any of the failures globals,
// and then release the lock once we're done modifying things. // and then release the lock once we're done modifying things.
failures_mutex.lock();
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d defer failures_mutex.unlock();
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
//
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
//
// failures_mutex.lock();
// defer failures_mutex.release();
//
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
const held = failures_mutex.acquire();
defer held.release();
// If we don't have enough capacity to add a failure, allocate a new failures pointer. // If we don't have enough capacity to add a failure, allocate a new failures pointer.
if (failure_length >= failure_capacity) { if (failure_length >= failure_capacity) {
@ -87,17 +77,8 @@ pub fn expectFailedC(
} }
pub fn getExpectFailures() []Failure { pub fn getExpectFailures() []Failure {
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d failures_mutex.lock();
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig defer failures_mutex.unlock();
//
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
//
// failures_mutex.lock();
// defer failures_mutex.release();
//
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
const held = failures_mutex.acquire();
defer held.release();
if (failure_length > 0) { if (failure_length > 0) {
// defensively clone failures, in case someone modifies the originals after the mutex has been released. // defensively clone failures, in case someone modifies the originals after the mutex has been released.
@ -116,23 +97,14 @@ pub fn getExpectFailures() []Failure {
} }
pub fn getExpectFailuresC() callconv(.C) CSlice { pub fn getExpectFailuresC() callconv(.C) CSlice {
var bytes = @ptrCast(*c_void, failures); var bytes = @ptrCast(*anyopaque, failures);
return .{ .pointer = bytes, .len = failure_length }; return .{ .pointer = bytes, .len = failure_length };
} }
pub fn deinitFailures() void { pub fn deinitFailures() void {
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d failures_mutex.lock();
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig defer failures_mutex.unlock();
//
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
//
// failures_mutex.lock();
// defer failures_mutex.release();
//
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
const held = failures_mutex.acquire();
defer held.release();
utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure)); utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure));
failure_length = 0; failure_length = 0;

View file

@ -1326,7 +1326,6 @@ pub fn listFindUnsafe(
data: Opaque, data: Opaque,
inc_n_data: IncN, inc_n_data: IncN,
data_is_owned: bool, data_is_owned: bool,
alignment: u32,
element_width: usize, element_width: usize,
inc: Inc, inc: Inc,
dec: Dec, dec: Dec,

View file

@ -177,7 +177,6 @@ comptime {
// setjmp/longjmp. LLVM is unable to generate code for longjmp on AArch64 (https://github.com/rtfeldman/roc/issues/2965), // setjmp/longjmp. LLVM is unable to generate code for longjmp on AArch64 (https://github.com/rtfeldman/roc/issues/2965),
// so instead we ask Zig to please provide implementations for us, which is does // so instead we ask Zig to please provide implementations for us, which is does
// (seemingly via musl). // (seemingly via musl).
pub usingnamespace @import("std").c.builtins;
pub extern fn setjmp([*c]c_int) c_int; pub extern fn setjmp([*c]c_int) c_int;
pub extern fn longjmp([*c]c_int, c_int) noreturn; pub extern fn longjmp([*c]c_int, c_int) noreturn;
pub extern fn _setjmp([*c]c_int) c_int; pub extern fn _setjmp([*c]c_int) c_int;

View file

@ -24,7 +24,7 @@ pub fn exportParseInt(comptime T: type, comptime name: []const u8) void {
const radix = 0; const radix = 0;
if (std.fmt.parseInt(T, buf.asSlice(), radix)) |success| { if (std.fmt.parseInt(T, buf.asSlice(), radix)) |success| {
return .{ .errorcode = 0, .value = success }; return .{ .errorcode = 0, .value = success };
} else |err| { } else |_| {
return .{ .errorcode = 1, .value = 0 }; return .{ .errorcode = 1, .value = 0 };
} }
} }
@ -37,7 +37,7 @@ pub fn exportParseFloat(comptime T: type, comptime name: []const u8) void {
fn func(buf: RocStr) callconv(.C) NumParseResult(T) { fn func(buf: RocStr) callconv(.C) NumParseResult(T) {
if (std.fmt.parseFloat(T, buf.asSlice())) |success| { if (std.fmt.parseFloat(T, buf.asSlice())) |success| {
return .{ .errorcode = 0, .value = success }; return .{ .errorcode = 0, .value = success };
} else |err| { } else |_| {
return .{ .errorcode = 1, .value = 0 }; return .{ .errorcode = 1, .value = 0 };
} }
} }

View file

@ -2041,7 +2041,7 @@ test "ReverseUtf8View: empty" {
const original_bytes = ""; const original_bytes = "";
var iter = ReverseUtf8View.initUnchecked(original_bytes).iterator(); var iter = ReverseUtf8View.initUnchecked(original_bytes).iterator();
while (iter.nextCodepoint()) |codepoint| { while (iter.nextCodepoint()) |_| {
try expect(false); try expect(false);
} }
} }

View file

@ -7,17 +7,17 @@ pub fn WithOverflow(comptime T: type) type {
} }
// If allocation fails, this must cxa_throw - it must not return a null pointer! // If allocation fails, this must cxa_throw - it must not return a null pointer!
extern fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void; extern fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque;
// This should never be passed a null pointer. // This should never be passed a null pointer.
// If allocation fails, this must cxa_throw - it must not return a null pointer! // If allocation fails, this must cxa_throw - it must not return a null pointer!
extern fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void; extern fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque;
// This should never be passed a null pointer. // This should never be passed a null pointer.
extern fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void; extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void;
// Signals to the host that the program has panicked // Signals to the host that the program has panicked
extern fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void; extern fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void;
// should work just like libc memcpy (we can't assume libc is present) // should work just like libc memcpy (we can't assume libc is present)
extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
@ -34,31 +34,31 @@ comptime {
} }
} }
fn testing_roc_alloc(size: usize, _: u32) callconv(.C) ?*c_void { fn testing_roc_alloc(size: usize, _: u32) callconv(.C) ?*anyopaque {
return @ptrCast(?*c_void, std.testing.allocator.alloc(u8, size) catch unreachable); return @ptrCast(?*anyopaque, std.testing.allocator.alloc(u8, size) catch unreachable);
} }
fn testing_roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, _: u32) callconv(.C) ?*c_void { fn testing_roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, _: u32) callconv(.C) ?*anyopaque {
const ptr = @ptrCast([*]u8, @alignCast(2 * @alignOf(usize), c_ptr)); const ptr = @ptrCast([*]u8, @alignCast(2 * @alignOf(usize), c_ptr));
const slice = ptr[0..old_size]; const slice = ptr[0..old_size];
return @ptrCast(?*c_void, std.testing.allocator.realloc(slice, new_size) catch unreachable); return @ptrCast(?*anyopaque, std.testing.allocator.realloc(slice, new_size) catch unreachable);
} }
fn testing_roc_dealloc(c_ptr: *c_void, _: u32) callconv(.C) void { fn testing_roc_dealloc(c_ptr: *anyopaque, _: u32) callconv(.C) void {
const ptr = @ptrCast([*]u8, @alignCast(2 * @alignOf(usize), c_ptr)); const ptr = @ptrCast([*]u8, @alignCast(2 * @alignOf(usize), c_ptr));
std.testing.allocator.destroy(ptr); std.testing.allocator.destroy(ptr);
} }
fn testing_roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { fn testing_roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = c_ptr; _ = c_ptr;
_ = tag_id; _ = tag_id;
@panic("Roc panicked"); @panic("Roc panicked");
} }
fn testing_roc_memcpy(dest: *c_void, src: *c_void, bytes: usize) callconv(.C) ?*c_void { fn testing_roc_memcpy(dest: *anyopaque, src: *anyopaque, bytes: usize) callconv(.C) ?*anyopaque {
const zig_dest = @ptrCast([*]u8, dest); const zig_dest = @ptrCast([*]u8, dest);
const zig_src = @ptrCast([*]u8, src); const zig_src = @ptrCast([*]u8, src);
@ -79,7 +79,7 @@ pub fn dealloc(c_ptr: [*]u8, alignment: u32) void {
} }
// must export this explicitly because right now it is not used from zig code // must export this explicitly because right now it is not used from zig code
pub fn panic(c_ptr: *c_void, alignment: u32) callconv(.C) void { pub fn panic(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
return @call(.{ .modifier = always_inline }, roc_panic, .{ c_ptr, alignment }); return @call(.{ .modifier = always_inline }, roc_panic, .{ c_ptr, alignment });
} }
@ -89,7 +89,7 @@ pub fn memcpy(dst: [*]u8, src: [*]u8, size: usize) void {
// indirection because otherwise zig creates an alias to the panic function which our LLVM code // indirection because otherwise zig creates an alias to the panic function which our LLVM code
// does not know how to deal with // does not know how to deal with
pub fn test_panic(c_ptr: *c_void, alignment: u32) callconv(.C) void { pub fn test_panic(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
_ = c_ptr; _ = c_ptr;
_ = alignment; _ = alignment;
// const cstr = @ptrCast([*:0]u8, c_ptr); // const cstr = @ptrCast([*:0]u8, c_ptr);
@ -240,7 +240,7 @@ pub fn allocateWithRefcount(
} }
pub const CSlice = extern struct { pub const CSlice = extern struct {
pointer: *c_void, pointer: *anyopaque,
len: usize, len: usize,
}; };

View file

@ -36,30 +36,15 @@ fn main() {
// LLVM .bc FILES // LLVM .bc FILES
generate_bc_file(&bitcode_path, &build_script_dir_path, "ir", "builtins-host"); generate_bc_file(&bitcode_path, "ir", "builtins-host");
if !DEBUG { if !DEBUG {
generate_bc_file( generate_bc_file(&bitcode_path, "ir-wasm32", "builtins-wasm32");
&bitcode_path,
&build_script_dir_path,
"ir-wasm32",
"builtins-wasm32",
);
} }
generate_bc_file( generate_bc_file(&bitcode_path, "ir-i386", "builtins-i386");
&bitcode_path,
&build_script_dir_path,
"ir-i386",
"builtins-i386",
);
generate_bc_file( generate_bc_file(&bitcode_path, "ir-x86_64", "builtins-x86_64");
&bitcode_path,
&build_script_dir_path,
"ir-x86_64",
"builtins-x86_64",
);
// OBJECT FILES // OBJECT FILES
#[cfg(windows)] #[cfg(windows)]
@ -131,35 +116,23 @@ fn generate_object_file(
} }
} }
fn generate_bc_file( fn generate_bc_file(bitcode_path: &Path, zig_object: &str, file_name: &str) {
bitcode_path: &Path,
build_script_dir_path: &Path,
zig_object: &str,
file_name: &str,
) {
let mut ll_path = bitcode_path.join(file_name); let mut ll_path = bitcode_path.join(file_name);
ll_path.set_extension("ll"); ll_path.set_extension("ll");
let dest_ir_host = ll_path.to_str().expect("Invalid dest ir path"); let dest_ir_host = ll_path.to_str().expect("Invalid dest ir path");
println!("Compiling host ir to: {}", dest_ir_host); println!("Compiling host ir to: {}", dest_ir_host);
let mut bc_path = bitcode_path.join(file_name);
bc_path.set_extension("bc");
let dest_bc_64bit = bc_path.to_str().expect("Invalid dest bc path");
println!("Compiling 64-bit bitcode to: {}", dest_bc_64bit);
run_command( run_command(
&bitcode_path, &bitcode_path,
&zig_executable(), &zig_executable(),
&["build", zig_object, "-Drelease=true"], &["build", zig_object, "-Drelease=true"],
); );
let mut bc_path = bitcode_path.join(file_name);
bc_path.set_extension("bc");
let dest_bc_64bit = bc_path.to_str().expect("Invalid dest bc path");
println!("Compiling 64-bit bitcode to: {}", dest_bc_64bit);
run_command(
&build_script_dir_path,
"llvm-as",
&[dest_ir_host, "-o", dest_bc_64bit],
);
} }
fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I) fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I)

View file

@ -68,6 +68,8 @@ use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, Unio
use roc_target::{PtrWidth, TargetInfo}; use roc_target::{PtrWidth, TargetInfo};
use target_lexicon::{Architecture, OperatingSystem, Triple}; use target_lexicon::{Architecture, OperatingSystem, Triple};
use super::convert::zig_with_overflow_roc_dec;
#[inline(always)] #[inline(always)]
fn print_fn_verification_output() -> bool { fn print_fn_verification_output() -> bool {
dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, { dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, {
@ -5246,6 +5248,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
argument_layouts, argument_layouts,
Layout::Builtin(Builtin::Bool), Layout::Builtin(Builtin::Bool),
); );
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout) list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
} }
_ => unreachable!("invalid list layout"), _ => unreachable!("invalid list layout"),
@ -5368,7 +5371,17 @@ fn run_low_level<'a, 'ctx, 'env>(
let string = load_symbol(scope, &args[0]); let string = load_symbol(scope, &args[0]);
call_bitcode_fn(env, &[string], intrinsic) let result = call_bitcode_fn(env, &[string], intrinsic);
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast
let expected_type = basic_type_from_layout(env, layout);
let actual_type = result.get_type();
if expected_type != actual_type {
complex_bitcast_check_size(env, result, expected_type, "str_to_num_cast")
} else {
result
}
} }
StrFromInt => { StrFromInt => {
// Str.fromInt : Int -> Str // Str.fromInt : Int -> Str
@ -7054,6 +7067,76 @@ fn build_float_binop<'a, 'ctx, 'env>(
} }
} }
fn dec_binop_with_overflow<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> StructValue<'ctx> {
let lhs = lhs.into_int_value();
let rhs = rhs.into_int_value();
let return_type = zig_with_overflow_roc_dec(env);
let return_alloca = env.builder.build_alloca(return_type, "return_alloca");
let int_64 = env.context.i128_type().const_int(64, false);
let int_64_type = env.context.i64_type();
let lhs1 = env
.builder
.build_right_shift(lhs, int_64, false, "lhs_left_bits");
let rhs1 = env
.builder
.build_right_shift(rhs, int_64, false, "rhs_left_bits");
call_void_bitcode_fn(
env,
&[
return_alloca.into(),
env.builder.build_int_cast(lhs, int_64_type, "").into(),
env.builder.build_int_cast(lhs1, int_64_type, "").into(),
env.builder.build_int_cast(rhs, int_64_type, "").into(),
env.builder.build_int_cast(rhs1, int_64_type, "").into(),
],
fn_name,
);
env.builder
.build_load(return_alloca, "load_dec")
.into_struct_value()
}
pub fn dec_binop_with_unchecked<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let lhs = lhs.into_int_value();
let rhs = rhs.into_int_value();
let int_64 = env.context.i128_type().const_int(64, false);
let int_64_type = env.context.i64_type();
let lhs1 = env
.builder
.build_right_shift(lhs, int_64, false, "lhs_left_bits");
let rhs1 = env
.builder
.build_right_shift(rhs, int_64, false, "rhs_left_bits");
call_bitcode_fn(
env,
&[
env.builder.build_int_cast(lhs, int_64_type, "").into(),
env.builder.build_int_cast(lhs1, int_64_type, "").into(),
env.builder.build_int_cast(rhs, int_64_type, "").into(),
env.builder.build_int_cast(rhs1, int_64_type, "").into(),
],
fn_name,
)
}
fn build_dec_binop<'a, 'ctx, 'env>( fn build_dec_binop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,
@ -7093,7 +7176,7 @@ fn build_dec_binop<'a, 'ctx, 'env>(
rhs, rhs,
"decimal multiplication overflowed", "decimal multiplication overflowed",
), ),
NumDivUnchecked => call_bitcode_fn(env, &[lhs, rhs], bitcode::DEC_DIV), NumDivUnchecked => dec_binop_with_unchecked(env, bitcode::DEC_DIV, lhs, rhs),
_ => { _ => {
unreachable!("Unrecognized int binary operation: {:?}", op); unreachable!("Unrecognized int binary operation: {:?}", op);
} }
@ -7108,15 +7191,7 @@ fn build_dec_binop_throw_on_overflow<'a, 'ctx, 'env>(
rhs: BasicValueEnum<'ctx>, rhs: BasicValueEnum<'ctx>,
message: &str, message: &str,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let overflow_type = crate::llvm::convert::zig_with_overflow_roc_dec(env); let result = dec_binop_with_overflow(env, operation, lhs, rhs);
let result_ptr = env.builder.build_alloca(overflow_type, "result_ptr");
call_void_bitcode_fn(env, &[result_ptr.into(), lhs, rhs], operation);
let result = env
.builder
.build_load(result_ptr, "load_overflow")
.into_struct_value();
let value = throw_on_overflow(env, parent, result, message).into_struct_value(); let value = throw_on_overflow(env, parent, result, message).into_struct_value();
@ -7211,6 +7286,9 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|| // Or if the two types are the same, they trivially fit. || // Or if the two types are the same, they trivially fit.
arg_width == target_int_width; arg_width == target_int_width;
let return_type =
convert::basic_type_from_layout(env, return_layout).into_struct_type();
if arg_always_fits_in_target { if arg_always_fits_in_target {
// This is guaranteed to succeed so we can just make it an int cast and let LLVM // This is guaranteed to succeed so we can just make it an int cast and let LLVM
// optimize it away. // optimize it away.
@ -7225,8 +7303,6 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
) )
.into(); .into();
let return_type =
convert::basic_type_from_layout(env, return_layout).into_struct_type();
let r = return_type.const_zero(); let r = return_type.const_zero();
let r = bd let r = bd
.build_insert_value(r, target_int_val, 0, "converted_int") .build_insert_value(r, target_int_val, 0, "converted_int")
@ -7249,7 +7325,14 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
&bitcode::NUM_INT_TO_INT_CHECKING_MAX_AND_MIN[target_int_width][arg_width] &bitcode::NUM_INT_TO_INT_CHECKING_MAX_AND_MIN[target_int_width][arg_width]
}; };
call_bitcode_fn_fixing_for_convention(env, &[arg.into()], return_layout, bitcode_fn) let result = call_bitcode_fn_fixing_for_convention(
env,
&[arg.into()],
return_layout,
bitcode_fn,
);
complex_bitcast_check_size(env, result, return_type.into(), "cast_bitpacked")
} }
} }
_ => { _ => {

View file

@ -283,6 +283,8 @@ pub fn dict_get<'a, 'ctx, 'env>(
.ptr_int() .ptr_int()
.const_int(value_layout.stack_size(env.target_info) as u64, false); .const_int(value_layout.stack_size(env.target_info) as u64, false);
let value_bt = basic_type_from_layout(env, value_layout);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info); let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context); let alignment_iv = alignment.as_int_value(env.context);
@ -308,17 +310,26 @@ pub fn dict_get<'a, 'ctx, 'env>(
) )
.into_struct_value(); .into_struct_value();
let flag = env let flag_u8 = env
.builder .builder
.build_extract_value(result, 1, "get_flag") .build_extract_value(result, 1, "get_flag")
.unwrap() .unwrap()
.into_int_value(); .into_int_value();
let flag = env
.builder
.build_int_cast(flag_u8, env.context.bool_type(), "to_bool");
let value_u8_ptr_int = env
.builder
.build_extract_value(result, 0, "get_value_ptr_int")
.unwrap()
.into_int_value();
let ptr_type = value_bt.ptr_type(AddressSpace::Generic);
let value_u8_ptr = env let value_u8_ptr = env
.builder .builder
.build_extract_value(result, 0, "get_value_ptr") .build_int_to_ptr(value_u8_ptr_int, ptr_type, "opaque_value_ptr");
.unwrap()
.into_pointer_value();
let start_block = env.builder.get_insert_block().unwrap(); let start_block = env.builder.get_insert_block().unwrap();
let parent = start_block.get_parent().unwrap(); let parent = start_block.get_parent().unwrap();
@ -326,7 +337,6 @@ pub fn dict_get<'a, 'ctx, 'env>(
let if_not_null = env.context.append_basic_block(parent, "if_not_null"); let if_not_null = env.context.append_basic_block(parent, "if_not_null");
let done_block = env.context.append_basic_block(parent, "done"); let done_block = env.context.append_basic_block(parent, "done");
let value_bt = basic_type_from_layout(env, value_layout);
let default = value_bt.const_zero(); let default = value_bt.const_zero();
env.builder env.builder

View file

@ -494,7 +494,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
layout_width(env, element_layout), layout_width(env, element_layout),
layout_width(env, function_call_return_layout), layout_width(env, function_call_return_layout),
layout_width(env, default_layout), layout_width(env, default_layout),
has_tag_id.as_global_value().as_pointer_value().into(), has_tag_id_helper(env, has_tag_id).into(),
dec_element_fn.as_global_value().as_pointer_value().into(), dec_element_fn.as_global_value().as_pointer_value().into(),
pass_as_opaque(env, result_ptr), pass_as_opaque(env, result_ptr),
], ],
@ -603,6 +603,30 @@ fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx>
BasicValueEnum::StructValue(struct_type.const_zero()) BasicValueEnum::StructValue(struct_type.const_zero())
} }
fn has_tag_id_helper<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
has_tag_id: FunctionValue<'ctx>,
) -> PointerValue<'ctx> {
let u8_t = env.context.i8_type();
let u16_t = env.context.i16_type();
let u8_ptr_t = u8_t.ptr_type(AddressSpace::Generic);
let struct_t = env
.context
.struct_type(&[u8_t.into(), env.ptr_int().into()], false);
let has_tag_id_type = struct_t
.fn_type(&[u16_t.into(), u8_ptr_t.into()], false)
.ptr_type(AddressSpace::Generic);
env.builder.build_pointer_cast(
has_tag_id.as_global_value().as_pointer_value(),
has_tag_id_type,
"has_tag_id_cast",
)
}
/// List.keepOks : List before, (before -> Result after *) -> List after /// List.keepOks : List before, (before -> Result after *) -> List after
pub fn list_keep_oks<'a, 'ctx, 'env>( pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
@ -626,7 +650,7 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
let has_tag_id = match result_layout { let has_tag_id = match result_layout {
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout), Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
Layout::Builtin(Builtin::Bool) => { Layout::Builtin(Builtin::Bool) => {
// a `Result [] whatever`, so there is nothing to keep // a `Result whatever []`, so there is nothing to keep
return empty_list(env); return empty_list(env);
} }
_ => unreachable!(), _ => unreachable!(),
@ -644,7 +668,7 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
layout_width(env, before_layout), layout_width(env, before_layout),
layout_width(env, result_layout), layout_width(env, result_layout),
layout_width(env, after_layout), layout_width(env, after_layout),
has_tag_id.as_global_value().as_pointer_value().into(), has_tag_id_helper(env, has_tag_id).into(),
dec_result_fn.as_global_value().as_pointer_value().into(), dec_result_fn.as_global_value().as_pointer_value().into(),
], ],
bitcode::LIST_KEEP_OKS, bitcode::LIST_KEEP_OKS,
@ -692,7 +716,7 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
layout_width(env, before_layout), layout_width(env, before_layout),
layout_width(env, result_layout), layout_width(env, result_layout),
layout_width(env, after_layout), layout_width(env, after_layout),
has_tag_id.as_global_value().as_pointer_value().into(), has_tag_id_helper(env, has_tag_id).into(),
dec_result_fn.as_global_value().as_pointer_value().into(), dec_result_fn.as_global_value().as_pointer_value().into(),
], ],
bitcode::LIST_KEEP_ERRS, bitcode::LIST_KEEP_ERRS,
@ -968,7 +992,6 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
pass_as_opaque(env, roc_function_call.data), pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(), roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(), roc_function_call.data_is_owned.into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout), layout_width(env, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(), inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(), dec_element_fn.as_global_value().as_pointer_value().into(),
@ -982,18 +1005,22 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
// in the Zig definition called above, because we don't know the size of the // in the Zig definition called above, because we don't know the size of the
// element until user compile time, which is later than the compile time of bitcode defs. // element until user compile time, which is later than the compile time of bitcode defs.
let value_u8_ptr = env let value_u8_ptr_int = env
.builder .builder
.build_extract_value(result, 0, "get_value_ptr") .build_extract_value(result, 0, "get_value_ptr_int")
.unwrap() .unwrap()
.into_pointer_value(); .into_int_value();
let found = env let found_u8 = env
.builder .builder
.build_extract_value(result, 1, "get_found") .build_extract_value(result, 1, "get_found")
.unwrap() .unwrap()
.into_int_value(); .into_int_value();
let found = env
.builder
.build_int_cast(found_u8, env.context.bool_type(), "found_as_bool");
let start_block = env.builder.get_insert_block().unwrap(); let start_block = env.builder.get_insert_block().unwrap();
let parent = start_block.get_parent().unwrap(); let parent = start_block.get_parent().unwrap();
@ -1007,14 +1034,13 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
.build_conditional_branch(found, if_not_null, done_block); .build_conditional_branch(found, if_not_null, done_block);
env.builder.position_at_end(if_not_null); env.builder.position_at_end(if_not_null);
let value_ptr = env
.builder let value_ptr = env.builder.build_int_to_ptr(
.build_bitcast( value_u8_ptr_int,
value_u8_ptr, value_bt.ptr_type(AddressSpace::Generic),
value_bt.ptr_type(AddressSpace::Generic), "get_value_ptr",
"from_opaque", );
)
.into_pointer_value();
let loaded = env.builder.build_load(value_ptr, "load_value"); let loaded = env.builder.build_load(value_ptr, "load_value");
env.builder.build_unconditional_branch(done_block); env.builder.build_unconditional_branch(done_block);

View file

@ -1,5 +1,5 @@
use crate::llvm::bitcode::{call_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn}; use crate::llvm::bitcode::{call_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::build::{complex_bitcast, Env, Scope}; use crate::llvm::build::{Env, Scope};
use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list}; use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list};
use inkwell::builder::Builder; use inkwell::builder::Builder;
use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue}; use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue};
@ -155,16 +155,22 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>(
let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap(); let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap();
let result_ptr = builder.build_alloca(result_type, "alloca_utf8_validate_bytes_result"); let result_ptr = builder.build_alloca(result_type, "alloca_utf8_validate_bytes_result");
let count = env
.builder
.build_extract_value(count_and_start, 0, "get_count")
.unwrap();
let start = env
.builder
.build_extract_value(count_and_start, 1, "get_start")
.unwrap();
call_void_bitcode_fn( call_void_bitcode_fn(
env, env,
&[ &[
list_symbol_to_c_abi(env, scope, list).into(), list_symbol_to_c_abi(env, scope, list).into(),
complex_bitcast( count,
env.builder, start,
count_and_start.into(),
env.twice_ptr_int().into(),
"to_i128",
),
result_ptr.into(), result_ptr.into(),
], ],
bitcode::STR_FROM_UTF8_RANGE, bitcode::STR_FROM_UTF8_RANGE,

View file

@ -1,4 +1,3 @@
use crate::llvm::bitcode::call_bitcode_fn;
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV}; use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
use crate::llvm::build_list::{list_len, load_list_ptr}; use crate::llvm::build_list::{list_len, load_list_ptr};
use crate::llvm::build_str::str_equal; use crate::llvm::build_str::str_equal;
@ -14,7 +13,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout}; use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use super::build::{load_roc_value, use_roc_value}; use super::build::{dec_binop_with_unchecked, load_roc_value, use_roc_value};
use super::convert::argument_type_from_union_layout; use super::convert::argument_type_from_union_layout;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -124,7 +123,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
} }
Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"), Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"),
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_EQ), Builtin::Decimal => dec_binop_with_unchecked(env, bitcode::DEC_EQ, lhs_val, rhs_val),
Builtin::Str => str_equal(env, lhs_val, rhs_val), Builtin::Str => str_equal(env, lhs_val, rhs_val),
Builtin::List(elem) => build_list_eq( Builtin::List(elem) => build_list_eq(
@ -289,7 +288,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
} }
Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"), Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"),
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_NEQ), Builtin::Decimal => dec_binop_with_unchecked(env, bitcode::DEC_NEQ, lhs_val, rhs_val),
Builtin::Str => { Builtin::Str => {
let is_equal = str_equal(env, lhs_val, rhs_val).into_int_value(); let is_equal = str_equal(env, lhs_val, rhs_val).into_int_value();

View file

@ -273,7 +273,10 @@ pub fn zig_str_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ct
} }
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> { pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
env.module.get_struct_type("list.HasTagId").unwrap() let u8_ptr_t = env.context.i8_type().ptr_type(AddressSpace::Generic);
env.context
.struct_type(&[env.context.bool_type().into(), u8_ptr_t.into()], false)
} }
pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> { pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {

View file

@ -21,12 +21,11 @@ use crate::storage::{Storage, StoredValue, StoredValueKind};
use crate::wasm_module::linking::{DataSymbol, LinkingSegment, WasmObjectSymbol}; use crate::wasm_module::linking::{DataSymbol, LinkingSegment, WasmObjectSymbol};
use crate::wasm_module::sections::{DataMode, DataSegment, Limits}; use crate::wasm_module::sections::{DataMode, DataSegment, Limits};
use crate::wasm_module::{ use crate::wasm_module::{
code_builder, CodeBuilder, Export, ExportType, LocalId, Signature, SymInfo, ValueType, code_builder, CodeBuilder, ExportType, LocalId, Signature, SymInfo, ValueType, WasmModule,
WasmModule,
}; };
use crate::{ use crate::{
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, MEMORY_NAME, copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, PTR_SIZE,
PTR_SIZE, PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, TARGET_INFO, PTR_TYPE, TARGET_INFO,
}; };
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -77,22 +76,32 @@ impl<'a> WasmBackend<'a> {
fn_index_offset: u32, fn_index_offset: u32,
helper_proc_gen: CodeGenHelp<'a>, helper_proc_gen: CodeGenHelp<'a>,
) -> Self { ) -> Self {
module.export.append(Export { // The preloaded builtins object file exports all functions, but the final app binary doesn't.
name: MEMORY_NAME.as_bytes(), // Remove the function exports and use them to populate the Name section (debug info)
ty: ExportType::Mem, let platform_and_builtins_exports =
index: 0, std::mem::replace(&mut module.export.exports, bumpalo::vec![in env.arena]);
}); let mut app_exports = Vec::with_capacity_in(32, env.arena);
module.export.append(Export { for ex in platform_and_builtins_exports.into_iter() {
name: STACK_POINTER_NAME.as_bytes(), match ex.ty {
ty: ExportType::Global, ExportType::Func => module.names.append_function(ex.index, ex.name),
index: STACK_POINTER_GLOBAL_ID, _ => app_exports.push(ex),
}); }
}
// The preloaded binary has a global to tell us where its data section ends // The preloaded binary has a global to tell us where its data section ends
// Note: We need this to account for zero data (.bss), which doesn't have an explicit DataSegment! // Note: We need this to account for zero data (.bss), which doesn't have an explicit DataSegment!
let data_end_idx = module.export.globals_lookup["__data_end".as_bytes()]; let data_end_name = "__data_end".as_bytes();
let data_end_idx = app_exports
.iter()
.find(|ex| ex.name == data_end_name)
.map(|ex| ex.index)
.unwrap_or_else(|| {
internal_error!("Preloaded Wasm binary must export global constant `__data_end`")
});
let next_constant_addr = module.global.parse_u32_at_index(data_end_idx); let next_constant_addr = module.global.parse_u32_at_index(data_end_idx);
module.export.exports = app_exports;
WasmBackend { WasmBackend {
env, env,
interns, interns,
@ -224,15 +233,19 @@ impl<'a> WasmBackend<'a> {
} }
fn start_proc(&mut self, proc: &Proc<'a>) { fn start_proc(&mut self, proc: &Proc<'a>) {
use ReturnMethod::*;
let ret_layout = WasmLayout::new(&proc.ret_layout); let ret_layout = WasmLayout::new(&proc.ret_layout);
let ret_type = match ret_layout.return_method() { let ret_type = match ret_layout.return_method(CallConv::C) {
ReturnMethod::Primitive(ty, _) => Some(ty), Primitive(ty, _) => Some(ty),
ReturnMethod::NoReturnValue => None, NoReturnValue => None,
ReturnMethod::WriteToPointerArg => { WriteToPointerArg => {
self.storage.arg_types.push(PTR_TYPE); self.storage.arg_types.push(PTR_TYPE);
None None
} }
ZigPackedStruct => {
internal_error!("C calling convention does not return Zig packed structs")
}
}; };
// Create a block so we can exit the function without skipping stack frame "pop" code. // Create a block so we can exit the function without skipping stack frame "pop" code.
@ -323,7 +336,7 @@ impl<'a> WasmBackend<'a> {
}; };
let mut n_inner_wasm_args = 0; let mut n_inner_wasm_args = 0;
let ret_type_and_size = match inner_ret_layout.return_method() { let ret_type_and_size = match inner_ret_layout.return_method(CallConv::C) {
ReturnMethod::NoReturnValue => None, ReturnMethod::NoReturnValue => None,
ReturnMethod::Primitive(ty, size) => { ReturnMethod::Primitive(ty, size) => {
// If the inner function returns a primitive, load the address to store it at // If the inner function returns a primitive, load the address to store it at
@ -337,6 +350,7 @@ impl<'a> WasmBackend<'a> {
n_inner_wasm_args += 1; n_inner_wasm_args += 1;
None None
} }
x => internal_error!("A Roc function should never use ReturnMethod {:?}", x),
}; };
// Load all the arguments for the inner function // Load all the arguments for the inner function
@ -1020,14 +1034,16 @@ impl<'a> WasmBackend<'a> {
return self.expr_call_low_level(lowlevel, arguments, ret_sym, ret_layout, ret_storage); return self.expr_call_low_level(lowlevel, arguments, ret_sym, ret_layout, ret_storage);
} }
let (param_types, ret_type) = self.storage.load_symbols_for_call( let (num_wasm_args, has_return_val, ret_zig_packed_struct) =
self.env.arena, self.storage.load_symbols_for_call(
&mut self.code_builder, self.env.arena,
arguments, &mut self.code_builder,
ret_sym, arguments,
&wasm_layout, ret_sym,
CallConv::C, &wasm_layout,
); CallConv::C,
);
debug_assert!(!ret_zig_packed_struct);
for (roc_proc_index, lookup) in self.proc_lookup.iter().enumerate() { for (roc_proc_index, lookup) in self.proc_lookup.iter().enumerate() {
let ProcLookupData { let ProcLookupData {
@ -1038,8 +1054,6 @@ impl<'a> WasmBackend<'a> {
} = lookup; } = lookup;
if *ir_sym == func_sym && pl == proc_layout { if *ir_sym == func_sym && pl == proc_layout {
let wasm_fn_index = self.fn_index_offset + roc_proc_index as u32; let wasm_fn_index = self.fn_index_offset + roc_proc_index as u32;
let num_wasm_args = param_types.len();
let has_return_val = ret_type.is_some();
self.code_builder.call( self.code_builder.call(
wasm_fn_index, wasm_fn_index,
*linker_sym_index, *linker_sym_index,

View file

@ -4,9 +4,6 @@ use roc_mono::layout::{Layout, UnionLayout};
use crate::wasm_module::ValueType; use crate::wasm_module::ValueType;
use crate::{PTR_SIZE, PTR_TYPE, TARGET_INFO}; use crate::{PTR_SIZE, PTR_TYPE, TARGET_INFO};
/// Manually keep up to date with the Zig version we are using for builtins
pub const BUILTINS_ZIG_VERSION: ZigVersion = ZigVersion::Zig8;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReturnMethod { pub enum ReturnMethod {
/// This layout is returned from a Wasm function "normally" as a Primitive /// This layout is returned from a Wasm function "normally" as a Primitive
@ -15,6 +12,8 @@ pub enum ReturnMethod {
WriteToPointerArg, WriteToPointerArg,
/// This layout is empty and requires no return value or argument (e.g. refcount helpers) /// This layout is empty and requires no return value or argument (e.g. refcount helpers)
NoReturnValue, NoReturnValue,
/// This layout is returned as a packed struct in an integer. Only used by Zig, not C.
ZigPackedStruct,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -124,33 +123,23 @@ impl WasmLayout {
} }
} }
pub fn return_method(&self) -> ReturnMethod { pub fn return_method(&self, conv: CallConv) -> ReturnMethod {
match self { match self {
Self::Primitive(ty, size) => ReturnMethod::Primitive(*ty, *size), Self::Primitive(ty, size) => ReturnMethod::Primitive(*ty, *size),
Self::StackMemory { size, .. } => { Self::StackMemory { size, format, .. } => {
if *size == 0 { conv.stack_memory_return_method(*size, *format)
ReturnMethod::NoReturnValue
} else {
ReturnMethod::WriteToPointerArg
}
} }
} }
} }
} }
#[derive(PartialEq, Eq)]
pub enum ZigVersion {
Zig8,
Zig9,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CallConv { pub enum CallConv {
/// The C calling convention, as defined here: /// The C calling convention, as defined here:
/// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md /// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
C, C,
/// The calling convention that Zig 0.8 or 0.9 generates for Wasm when we *ask* it /// The calling convention that Zig 0.9 generates for Wasm when we *ask* it
/// for the .C calling convention, due to bugs in both versions of the Zig compiler. /// for the .C calling convention, due to bugs in the Zig compiler.
Zig, Zig,
} }
@ -182,7 +171,7 @@ impl CallConv {
&[I32] // Small struct: pass by value &[I32] // Small struct: pass by value
} else if size <= 8 { } else if size <= 8 {
&[I64] // Small struct: pass by value &[I64] // Small struct: pass by value
} else if size <= 12 && BUILTINS_ZIG_VERSION == ZigVersion::Zig9 { } else if size <= 12 {
&[I64, I32] // Medium struct: pass by value, as two Wasm arguments &[I64, I32] // Medium struct: pass by value, as two Wasm arguments
} else if size <= 16 { } else if size <= 16 {
&[I64, I64] // Medium struct: pass by value, as two Wasm arguments &[I64, I64] // Medium struct: pass by value, as two Wasm arguments
@ -194,4 +183,30 @@ impl CallConv {
} }
} }
} }
pub fn stack_memory_return_method(&self, size: u32, format: StackMemoryFormat) -> ReturnMethod {
use ReturnMethod::*;
use StackMemoryFormat::*;
match format {
Int128 | Float128 | Decimal => WriteToPointerArg,
DataStructure => {
if size == 0 {
return NoReturnValue;
}
match self {
CallConv::C => WriteToPointerArg,
CallConv::Zig => {
if size <= 8 {
ZigPackedStruct
} else {
WriteToPointerArg
}
}
}
}
}
}
} }

View file

@ -136,7 +136,7 @@ impl<'a> LowLevelCall<'a> {
/// For numerical ops, this just pushes the arguments to the Wasm VM's value stack /// For numerical ops, this just pushes the arguments to the Wasm VM's value stack
/// It implements the calling convention used by Zig for both numbers and structs /// It implements the calling convention used by Zig for both numbers and structs
/// Result is the type signature of the call /// Result is the type signature of the call
fn load_args(&self, backend: &mut WasmBackend<'a>) -> (Vec<'a, ValueType>, Option<ValueType>) { fn load_args(&self, backend: &mut WasmBackend<'a>) -> (usize, bool, bool) {
backend.storage.load_symbols_for_call( backend.storage.load_symbols_for_call(
backend.env.arena, backend.env.arena,
&mut backend.code_builder, &mut backend.code_builder,
@ -148,8 +148,29 @@ impl<'a> LowLevelCall<'a> {
} }
fn load_args_and_call_zig(&self, backend: &mut WasmBackend<'a>, name: &'a str) { fn load_args_and_call_zig(&self, backend: &mut WasmBackend<'a>, name: &'a str) {
let (param_types, ret_type) = self.load_args(backend); let (num_wasm_args, has_return_val, ret_zig_packed_struct) = self.load_args(backend);
backend.call_zig_builtin_after_loading_args(name, param_types.len(), ret_type.is_some()); backend.call_zig_builtin_after_loading_args(name, num_wasm_args, has_return_val);
if ret_zig_packed_struct {
match self.ret_storage {
StoredValue::StackMemory {
size,
alignment_bytes,
..
} => {
// The address of the return value was already loaded before the call
let align = Align::from(alignment_bytes);
if size > 4 {
backend.code_builder.i64_store(align, 0);
} else {
backend.code_builder.i32_store(align, 0);
}
}
_ => {
internal_error!("Zig packed struct should always be stored to StackMemory")
}
}
}
} }
/// Wrap an integer whose Wasm representation is i32 /// Wrap an integer whose Wasm representation is i32

View file

@ -6,9 +6,7 @@ use roc_error_macros::internal_error;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
use crate::layout::{ use crate::layout::{CallConv, ReturnMethod, StackMemoryFormat, WasmLayout};
CallConv, ReturnMethod, StackMemoryFormat, WasmLayout, ZigVersion, BUILTINS_ZIG_VERSION,
};
use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState}; use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_TYPE}; use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_TYPE};
@ -327,7 +325,7 @@ impl<'a> Storage<'a> {
code_builder.i32_load(align, offset); code_builder.i32_load(align, offset);
} else if *size <= 8 { } else if *size <= 8 {
code_builder.i64_load(align, offset); code_builder.i64_load(align, offset);
} else if *size <= 12 && BUILTINS_ZIG_VERSION == ZigVersion::Zig9 { } else if *size <= 12 {
code_builder.i64_load(align, offset); code_builder.i64_load(align, offset);
code_builder.get_local(local_id); code_builder.get_local(local_id);
code_builder.i32_load(align, offset + 8); code_builder.i32_load(align, offset + 8);
@ -397,37 +395,47 @@ impl<'a> Storage<'a> {
return_symbol: Symbol, return_symbol: Symbol,
return_layout: &WasmLayout, return_layout: &WasmLayout,
call_conv: CallConv, call_conv: CallConv,
) -> (Vec<'a, ValueType>, Option<ValueType>) { ) -> (usize, bool, bool) {
let mut wasm_arg_types = Vec::with_capacity_in(arguments.len() * 2 + 1, arena); use ReturnMethod::*;
let mut wasm_args = Vec::with_capacity_in(arguments.len() * 2 + 1, arena);
let return_method = return_layout.return_method(); let mut num_wasm_args = 0;
let return_type = match return_method { let mut symbols_to_load = Vec::with_capacity_in(arguments.len() * 2 + 1, arena);
ReturnMethod::Primitive(ty, _) => Some(ty),
ReturnMethod::NoReturnValue => None, let return_method = return_layout.return_method(call_conv);
ReturnMethod::WriteToPointerArg => { let has_return_val = match return_method {
wasm_arg_types.push(PTR_TYPE); Primitive(..) => true,
wasm_args.push(return_symbol); NoReturnValue => false,
None WriteToPointerArg => {
num_wasm_args += 1;
symbols_to_load.push(return_symbol);
false
}
ZigPackedStruct => {
// Workaround for Zig's incorrect implementation of the C calling convention.
// We need to copy the packed struct into the stack frame
// Load the address before the call so that afterward, it will be 2nd on the value stack,
// ready for the store instruction.
symbols_to_load.push(return_symbol);
true
} }
}; };
for arg in arguments { for arg in arguments {
let stored = self.symbol_storage_map.get(arg).unwrap(); let stored = self.symbol_storage_map.get(arg).unwrap();
let arg_types = stored.arg_types(call_conv); let arg_types = stored.arg_types(call_conv);
wasm_arg_types.extend_from_slice(arg_types); num_wasm_args += arg_types.len();
match arg_types.len() { match arg_types.len() {
0 => {} 0 => {}
1 => wasm_args.push(*arg), 1 => symbols_to_load.push(*arg),
2 => wasm_args.extend_from_slice(&[*arg, *arg]), 2 => symbols_to_load.extend_from_slice(&[*arg, *arg]),
n => internal_error!("Cannot have {} Wasm arguments for 1 Roc argument", n), n => internal_error!("Cannot have {} Wasm arguments for 1 Roc argument", n),
} }
} }
// If the symbols were already at the top of the stack, do nothing! // If the symbols were already at the top of the stack, do nothing!
// Should be common for simple cases, due to the structure of the Mono IR // Should be common for simple cases, due to the structure of the Mono IR
if !code_builder.verify_stack_match(&wasm_args) { if !code_builder.verify_stack_match(&symbols_to_load) {
if return_method == ReturnMethod::WriteToPointerArg { if matches!(return_method, WriteToPointerArg | ZigPackedStruct) {
self.load_return_address_ccc(code_builder, return_symbol); self.load_return_address_ccc(code_builder, return_symbol);
}; };
@ -439,7 +447,11 @@ impl<'a> Storage<'a> {
} }
} }
(wasm_arg_types, return_type) (
num_wasm_args,
has_return_val,
return_method == ZigPackedStruct,
)
} }
/// Generate code to copy a StoredValue to an arbitrary memory location /// Generate code to copy a StoredValue to an arbitrary memory location

View file

@ -5,7 +5,7 @@ pub mod opcodes;
pub mod sections; pub mod sections;
pub mod serialize; pub mod serialize;
use bumpalo::Bump; use bumpalo::{collections::Vec, Bump};
pub use code_builder::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState}; pub use code_builder::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
pub use linking::SymInfo; pub use linking::SymInfo;
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
@ -145,7 +145,7 @@ impl<'a> WasmModule<'a> {
let global = GlobalSection::preload(arena, bytes, &mut cursor); let global = GlobalSection::preload(arena, bytes, &mut cursor);
let export = ExportSection::preload_globals(arena, bytes, &mut cursor); let export = ExportSection::preload(arena, bytes, &mut cursor);
let start = OpaqueSection::preload(SectionId::Start, arena, bytes, &mut cursor); let start = OpaqueSection::preload(SectionId::Start, arena, bytes, &mut cursor);
@ -191,10 +191,18 @@ impl<'a> WasmModule<'a> {
arena: &'a Bump, arena: &'a Bump,
called_preload_fns: T, called_preload_fns: T,
) { ) {
let exported_fn_iter = self
.export
.exports
.iter()
.filter(|ex| ex.ty == ExportType::Func)
.map(|ex| ex.index);
let function_indices = Vec::from_iter_in(exported_fn_iter, arena);
self.code.remove_dead_preloads( self.code.remove_dead_preloads(
arena, arena,
self.import.function_count, self.import.function_count,
&self.export.function_indices, &function_indices,
called_preload_fns, called_preload_fns,
) )
} }

View file

@ -115,7 +115,7 @@ fn section_size(bytes: &[u8]) -> usize {
} }
fn parse_section<'a>(id: SectionId, module_bytes: &'a [u8], cursor: &mut usize) -> (u32, &'a [u8]) { fn parse_section<'a>(id: SectionId, module_bytes: &'a [u8], cursor: &mut usize) -> (u32, &'a [u8]) {
if module_bytes[*cursor] != id as u8 { if (*cursor >= module_bytes.len()) || (module_bytes[*cursor] != id as u8) {
return (0, &[]); return (0, &[]);
} }
*cursor += 1; *cursor += 1;
@ -809,56 +809,35 @@ impl Serialize for Export<'_> {
#[derive(Debug)] #[derive(Debug)]
pub struct ExportSection<'a> { pub struct ExportSection<'a> {
pub count: u32, pub exports: Vec<'a, Export<'a>>,
pub bytes: Vec<'a, u8>,
/// List of exported functions to keep during dead-code-elimination
pub function_indices: Vec<'a, u32>,
/// name -> index
pub globals_lookup: MutMap<&'a [u8], u32>,
} }
impl<'a> ExportSection<'a> { impl<'a> ExportSection<'a> {
const ID: SectionId = SectionId::Export; const ID: SectionId = SectionId::Export;
pub fn append(&mut self, export: Export) { pub fn append(&mut self, export: Export<'a>) {
export.serialize(&mut self.bytes); self.exports.push(export);
self.count += 1;
if matches!(export.ty, ExportType::Func) {
self.function_indices.push(export.index);
}
} }
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
section_size(&self.bytes) self.exports
.iter()
.map(|ex| ex.name.len() + 1 + MAX_SIZE_ENCODED_U32)
.sum()
} }
fn empty(arena: &'a Bump) -> Self { /// Preload from object file.
ExportSection { pub fn preload(arena: &'a Bump, module_bytes: &[u8], cursor: &mut usize) -> Self {
count: 0,
bytes: Vec::with_capacity_in(256, arena),
function_indices: Vec::with_capacity_in(4, arena),
globals_lookup: MutMap::default(),
}
}
/// Preload from object file. Keep only the Global exports, ignore the rest.
pub fn preload_globals(arena: &'a Bump, module_bytes: &[u8], cursor: &mut usize) -> Self {
let (num_exports, body_bytes) = parse_section(Self::ID, module_bytes, cursor); let (num_exports, body_bytes) = parse_section(Self::ID, module_bytes, cursor);
let mut export_section = ExportSection::empty(arena); let mut export_section = ExportSection {
exports: Vec::with_capacity_in(num_exports as usize, arena),
};
let mut body_cursor = 0; let mut body_cursor = 0;
for _ in 0..num_exports { while body_cursor < body_bytes.len() {
let export_start = body_cursor;
let export = Export::parse(arena, body_bytes, &mut body_cursor); let export = Export::parse(arena, body_bytes, &mut body_cursor);
if matches!(export.ty, ExportType::Global) { export_section.exports.push(export);
let global_bytes = &body_bytes[export_start..body_cursor];
export_section.bytes.extend_from_slice(global_bytes);
export_section.count += 1;
export_section
.globals_lookup
.insert(export.name, export.index);
}
} }
export_section export_section
@ -867,10 +846,9 @@ impl<'a> ExportSection<'a> {
impl<'a> Serialize for ExportSection<'a> { impl<'a> Serialize for ExportSection<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
if !self.bytes.is_empty() { if !self.exports.is_empty() {
let header_indices = write_section_header(buffer, Self::ID); let header_indices = write_section_header(buffer, Self::ID);
buffer.encode_u32(self.count); self.exports.serialize(buffer);
buffer.append_slice(&self.bytes);
update_section_size(buffer, header_indices); update_section_size(buffer, header_indices);
} }
} }
@ -1291,6 +1269,14 @@ impl<'a> NameSection<'a> {
} }
pub fn parse(arena: &'a Bump, module_bytes: &[u8], cursor: &mut usize) -> Self { pub fn parse(arena: &'a Bump, module_bytes: &[u8], cursor: &mut usize) -> Self {
// If we're already past the end of the preloaded file then there is no Name section
if *cursor >= module_bytes.len() {
return NameSection {
bytes: bumpalo::vec![in arena],
functions: MutMap::default(),
};
}
// Custom section ID // Custom section ID
let section_id_byte = module_bytes[*cursor]; let section_id_byte = module_bytes[*cursor];
if section_id_byte != Self::ID as u8 { if section_id_byte != Self::ID as u8 {

View file

@ -1,7 +1,7 @@
use roc_builtins::bitcode; use roc_builtins::bitcode;
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
const PLATFORM_FILENAME: &str = "wasm_test_platform"; const PLATFORM_FILENAME: &str = "wasm_test_platform";
@ -15,11 +15,44 @@ fn main() {
} }
fn build_wasm() { fn build_wasm() {
let out_dir = env::var("OUT_DIR").unwrap(); let source_path = format!("src/helpers/{}.c", PLATFORM_FILENAME);
println!("cargo:rerun-if-changed={}", source_path);
let out_dir = env::var("OUT_DIR").unwrap();
println!("cargo:rustc-env={}={}", OUT_DIR_VAR, out_dir); println!("cargo:rustc-env={}={}", OUT_DIR_VAR, out_dir);
build_wasm_platform_and_builtins(&out_dir); // Zig can produce *either* an object containing relocations OR an object containing libc code
// But we want both, so we have to compile twice with different flags, then link them
// Create an object file with relocations
let platform_path = build_wasm_platform(&out_dir, &source_path);
// Compile again to get libc path
let (libc_path, compiler_rt_path) = build_wasm_libc_compilerrt(&out_dir, &source_path);
let mut libc_pathbuf = PathBuf::from(&libc_path);
libc_pathbuf.pop();
let libc_dir = libc_pathbuf.to_str().unwrap();
let args = &[
"wasm-ld",
bitcode::BUILTINS_WASM32_OBJ_PATH,
&platform_path,
&compiler_rt_path,
"-L",
libc_dir,
"-lc",
"-o",
&format!("{}/{}.o", out_dir, PLATFORM_FILENAME),
"--export-all",
"--no-entry",
// "--emit-relocs", // TODO: resize stack by relocating __heap_base (issue #2480) here and in repl_test build
];
let zig = zig_executable();
// println!("{} {}", zig, args.join(" "));
run_command(&zig, args);
} }
fn zig_executable() -> String { fn zig_executable() -> String {
@ -29,29 +62,46 @@ fn zig_executable() -> String {
} }
} }
/// Create an all-in-one object file: platform + builtins + libc fn build_wasm_platform(out_dir: &str, source_path: &str) -> String {
fn build_wasm_platform_and_builtins(out_dir: &str) { let platform_path = format!("{}/{}.o", out_dir, PLATFORM_FILENAME);
println!("cargo:rerun-if-changed=src/helpers/{}.c", PLATFORM_FILENAME);
// See discussion with Luuk de Gram (Zig contributor) run_command(
// https://github.com/rtfeldman/roc/pull/2181#pullrequestreview-839608063 &zig_executable(),
// This builds a library file that exports everything. It has no linker data but we don't need that. &[
let args = [ "build-lib",
"build-lib", "-target",
"-target", "wasm32-wasi",
"wasm32-wasi", "-lc",
"-lc", source_path,
"-dynamic", // -dynamic ensures libc code goes into the binary &format!("-femit-bin={}", &platform_path),
bitcode::BUILTINS_WASM32_OBJ_PATH, ],
&format!("src/helpers/{}.c", PLATFORM_FILENAME), );
&format!("-femit-bin={}/{}.o", out_dir, PLATFORM_FILENAME),
];
let zig = zig_executable(); platform_path
}
// println!("{} {}", zig, args.join(" ")); fn build_wasm_libc_compilerrt(out_dir: &str, source_path: &str) -> (String, String) {
let zig_cache_dir = format!("{}/zig-cache-wasm32", out_dir);
run_command(Path::new("."), &zig, args); run_command(
&zig_executable(),
&[
"build-lib",
"-dynamic", // ensure libc code is actually generated (not just linked against header)
"-target",
"wasm32-wasi",
"-lc",
source_path,
"-femit-bin=/dev/null",
"--global-cache-dir",
&zig_cache_dir,
],
);
(
run_command("find", &[&zig_cache_dir, "-name", "libc.a"]),
run_command("find", &[&zig_cache_dir, "-name", "compiler_rt.o"]),
)
} }
fn feature_is_enabled(feature_name: &str) -> bool { fn feature_is_enabled(feature_name: &str) -> bool {
@ -62,26 +112,35 @@ fn feature_is_enabled(feature_name: &str) -> bool {
env::var(cargo_env_var).is_ok() env::var(cargo_env_var).is_ok()
} }
fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I) -> String fn run_command(command_str: &str, args: &[&str]) -> String {
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let output_result = Command::new(OsStr::new(&command_str)) let output_result = Command::new(OsStr::new(&command_str))
.current_dir(path) .current_dir(Path::new("."))
.args(args) .args(args)
.output(); .output();
let fail = |err: String| {
panic!(
"\n\nFailed command:\n\t{} {}\n\n{}",
command_str,
args.join(" "),
err
);
};
match output_result { match output_result {
Ok(output) => match output.status.success() { Ok(output) => match output.status.success() {
true => std::str::from_utf8(&output.stdout).unwrap().to_string(), true => std::str::from_utf8(&output.stdout)
.unwrap()
.trim()
.to_string(),
false => { false => {
let error_str = match std::str::from_utf8(&output.stderr) { let error_str = match std::str::from_utf8(&output.stderr) {
Ok(stderr) => stderr.to_string(), Ok(stderr) => stderr.to_string(),
Err(_) => format!("Failed to run \"{}\"", command_str), Err(_) => format!("Failed to run \"{}\"", command_str),
}; };
panic!("{} failed: {}", command_str, error_str); fail(error_str)
} }
}, },
Err(reason) => panic!("{} failed: {}", command_str, reason), Err(reason) => fail(reason.to_string()),
} }
} }

View file

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
// Makes test runs take 50% longer, due to linking // Makes test runs take 50% longer, due to linking
#define ENABLE_PRINTF 0 #define ENABLE_PRINTF 0
@ -138,9 +139,9 @@ void roc_panic(char *msg, unsigned int tag_id)
//-------------------------- //--------------------------
void *roc_memcpy(void *dest, const void *src, size_t n) void roc_memcpy(void *dest, const void *src, size_t n)
{ {
return memcpy(dest, src, n); memcpy(dest, src, n);
} }
//-------------------------- //--------------------------

View file

@ -2,6 +2,7 @@ const std = @import("std");
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;
const expect = testing.expect; const expect = testing.expect;
const maxInt = std.math.maxInt;
comptime { comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218 // This is a workaround for https://github.com/ziglang/zig/issues/8218
@ -12,7 +13,8 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -24,14 +26,16 @@ const Allocator = mem.Allocator;
// extern fn roc__mainForHost_1_exposed(i64, *i64) void; // extern fn roc__mainForHost_1_exposed(i64, *i64) void;
extern fn roc__mainForHost_1_exposed(i64) i64; extern fn roc__mainForHost_1_exposed(i64) i64;
const Align = extern struct { a: usize, b: usize }; const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false; const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
var ptr = malloc(size); var ptr = malloc(size);
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
@ -42,25 +46,25 @@ export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
} }
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
} }
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
} }
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr))); free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id; _ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
@ -69,19 +73,27 @@ export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
std.process.exit(0); std.process.exit(0);
} }
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
return memcpy(dst, src, size);
}
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
return memset(dst, value, size);
}
pub export fn main() u8 { pub export fn main() u8 {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
// start time // start time
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
const result = roc__mainForHost_1_exposed(10); const result = roc__mainForHost_1_exposed(10);
// end time // end time
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
stdout.print("{d}\n", .{result}) catch unreachable; stdout.print("{d}\n", .{result}) catch unreachable;

View file

@ -1,4 +1,7 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;
const expect = testing.expect; const expect = testing.expect;
@ -12,7 +15,7 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -21,18 +24,17 @@ const mem = std.mem;
const Allocator = mem.Allocator; const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed_generic(output: *RocList, input: *RocList) void; extern fn roc__mainForHost_1_exposed_generic(output: *RocList, input: *RocList) void;
// extern fn roc__mainForHost_1_exposed_generic(input: *RocList) RocList;
const Align = extern struct { a: usize, b: usize }; const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false; const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
var ptr = malloc(size); var ptr = malloc(size);
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
@ -43,25 +45,25 @@ export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
} }
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
} }
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
} }
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr))); free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id; _ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
@ -87,7 +89,6 @@ const Unit = extern struct {};
pub export fn main() u8 { pub export fn main() u8 {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
var raw_numbers: [NUM_NUMS + 1]i64 = undefined; var raw_numbers: [NUM_NUMS + 1]i64 = undefined;
@ -104,7 +105,7 @@ pub export fn main() u8 {
// start time // start time
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
// actually call roc to populate the callresult // actually call roc to populate the callresult
var callresult: RocList = undefined; var callresult: RocList = undefined;
@ -118,7 +119,7 @@ pub export fn main() u8 {
// end time // end time
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
for (result) |x, i| { for (result) |x, i| {
if (i == 0) { if (i == 0) {

View file

@ -15,7 +15,8 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -30,15 +31,15 @@ extern fn roc__mainForHost_1_Fx_size() i64;
extern fn roc__mainForHost_1_Fx_result_size() i64; extern fn roc__mainForHost_1_Fx_result_size() i64;
const Align = 2 * @alignOf(usize); const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false; const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
var ptr = malloc(size); var ptr = malloc(size);
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
@ -49,7 +50,7 @@ export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
} }
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
@ -58,7 +59,7 @@ export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignmen
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
@ -67,7 +68,7 @@ export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
free(@alignCast(Align, @ptrCast([*]u8, c_ptr))); free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id; _ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
@ -98,7 +99,7 @@ pub export fn main() callconv(.C) u8 {
} }
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
roc__mainForHost_1_exposed_generic(output); roc__mainForHost_1_exposed_generic(output);
@ -107,7 +108,7 @@ pub export fn main() callconv(.C) u8 {
call_the_closure(closure_data_pointer); call_the_closure(closure_data_pointer);
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
const delta = to_seconds(ts2) - to_seconds(ts1); const delta = to_seconds(ts2) - to_seconds(ts1);
@ -214,8 +215,3 @@ fn roc_fx_getInt_help() !i64 {
return std.fmt.parseInt(i64, line, 10); return std.fmt.parseInt(i64, line, 10);
} }
fn readLine() []u8 {
const stdin = std.io.getStdIn().reader();
return (stdin.readUntilDelimiterOrEof(&line_buf, '\n') catch unreachable) orelse "";
}

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const str = @import("str"); const str = @import("str");
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
@ -14,21 +15,21 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
const Align = 2 * @alignOf(usize); const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false; const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
var ptr = malloc(size); var ptr = malloc(size);
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
@ -39,7 +40,7 @@ export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
} }
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
@ -48,7 +49,7 @@ export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignmen
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
@ -57,7 +58,7 @@ export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
free(@alignCast(Align, @ptrCast([*]u8, c_ptr))); free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id; _ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
@ -87,7 +88,7 @@ pub fn main() u8 {
// start time // start time
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
// actually call roc to populate the callresult // actually call roc to populate the callresult
var callresult = RocStr.empty(); var callresult = RocStr.empty();
@ -95,7 +96,7 @@ pub fn main() u8 {
// end time // end time
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
// stdout the result // stdout the result
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable; stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;

View file

@ -15,7 +15,8 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -29,25 +30,47 @@ extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
extern fn roc__mainForHost_1_Fx_size() i64; extern fn roc__mainForHost_1_Fx_size() i64;
extern fn roc__mainForHost_1_Fx_result_size() i64; extern fn roc__mainForHost_1_Fx_result_size() i64;
extern fn malloc(size: usize) callconv(.C) ?*c_void; const Align = 2 * @alignOf(usize);
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { const DEBUG: bool = false;
return malloc(size);
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) {
var ptr = malloc(size);
const stdout = std.io.getStdOut().writer();
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
return ptr;
} else {
return malloc(size);
}
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size); if (DEBUG) {
const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
}
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
free(@alignCast(16, @ptrCast([*]u8, c_ptr))); if (DEBUG) {
const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
}
free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
const msg = @ptrCast([*:0]const u8, c_ptr); const msg = @ptrCast([*:0]const u8, c_ptr);
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable; stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
@ -67,7 +90,6 @@ const Unit = extern struct {};
pub export fn main() u8 { pub export fn main() u8 {
const allocator = std.heap.page_allocator; const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
// NOTE the return size can be zero, which will segfault. Always allocate at least 8 bytes // NOTE the return size can be zero, which will segfault. Always allocate at least 8 bytes
@ -80,14 +102,14 @@ pub export fn main() u8 {
} }
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
roc__mainForHost_1_exposed_generic(output); roc__mainForHost_1_exposed_generic(output);
call_the_closure(output); call_the_closure(output);
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
const delta = to_seconds(ts2) - to_seconds(ts1); const delta = to_seconds(ts2) - to_seconds(ts1);
@ -130,11 +152,7 @@ fn call_the_closure(closure_data_pointer: [*]u8) void {
} }
pub export fn roc_fx_getLine() str.RocStr { pub export fn roc_fx_getLine() str.RocStr {
if (roc_fx_getLine_help()) |value| { return roc_fx_getLine_help() catch return str.RocStr.empty();
return value;
} else |err| {
return str.RocStr.empty();
}
} }
fn roc_fx_getLine_help() !RocStr { fn roc_fx_getLine_help() !RocStr {
@ -188,8 +206,3 @@ fn roc_fx_getInt_help() !i64 {
return std.fmt.parseInt(i64, line, 10); return std.fmt.parseInt(i64, line, 10);
} }
fn readLine() []u8 {
const stdin = std.io.getStdIn().reader();
return (stdin.readUntilDelimiterOrEof(&line_buf, '\n') catch unreachable) orelse "";
}

View file

@ -15,7 +15,8 @@ comptime {
// -fcompiler-rt in link.rs instead of doing this. Note that this // -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo // workaround is present in many host.zig files, so make sure to undo
// it everywhere! // it everywhere!
if (std.builtin.os.tag == .macos) { const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt"); _ = @import("compiler_rt");
} }
} }
@ -79,15 +80,15 @@ fn view(input: ConstModel) RocStr {
} }
const Align = 2 * @alignOf(usize); const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void; extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void; extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void; extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void; extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void; extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
const DEBUG: bool = false; const DEBUG: bool = false;
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
var ptr = malloc(size); var ptr = malloc(size);
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
@ -98,7 +99,7 @@ export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
} }
} }
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void { export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable; stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
@ -107,7 +108,7 @@ export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignmen
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size); return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
} }
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void { export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
if (DEBUG) { if (DEBUG) {
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable; stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
@ -116,7 +117,7 @@ export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
free(@alignCast(Align, @ptrCast([*]u8, c_ptr))); free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
} }
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void { export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
_ = tag_id; _ = tag_id;
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
@ -136,17 +137,15 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
const Unit = extern struct {}; const Unit = extern struct {};
pub export fn main() callconv(.C) u8 { pub export fn main() callconv(.C) u8 {
const allocator = std.heap.page_allocator;
var ts1: std.os.timespec = undefined; var ts1: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts1) catch unreachable;
const program = roc__mainForHost_1_exposed(); const program = roc__mainForHost_1_exposed();
call_the_closure(program); call_the_closure(program);
var ts2: std.os.timespec = undefined; var ts2: std.os.timespec = undefined;
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; std.os.clock_gettime(std.os.CLOCK.REALTIME, &ts2) catch unreachable;
const delta = to_seconds(ts2) - to_seconds(ts1); const delta = to_seconds(ts2) - to_seconds(ts1);
@ -161,13 +160,15 @@ fn to_seconds(tms: std.os.timespec) f64 {
} }
fn call_the_closure(program: Program) void { fn call_the_closure(program: Program) void {
const allocator = std.heap.page_allocator; _ = program;
var allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer(); const stdout = std.io.getStdOut().writer();
const stdin = std.io.getStdIn().reader(); const stdin = std.io.getStdIn().reader();
var buf: [1000]u8 = undefined; var buf: [1000]u8 = undefined;
var model = init(allocator); var model = init(&allocator);
while (true) { while (true) {
const line = (stdin.readUntilDelimiterOrEof(buf[0..], '\n') catch unreachable) orelse return; const line = (stdin.readUntilDelimiterOrEof(buf[0..], '\n') catch unreachable) orelse return;
@ -178,7 +179,7 @@ fn call_the_closure(program: Program) void {
const to_append = RocStr.init(line.ptr, line.len); const to_append = RocStr.init(line.ptr, line.len);
model = update(allocator, model, to_append); model = update(&allocator, model, to_append);
const viewed = view(model); const viewed = view(model);
for (viewed.asSlice()) |char| { for (viewed.asSlice()) |char| {
@ -266,8 +267,3 @@ fn roc_fx_getInt_help() !i64 {
return std.fmt.parseInt(i64, line, 10); return std.fmt.parseInt(i64, line, 10);
} }
fn readLine() []u8 {
const stdin = std.io.getStdIn().reader();
return (stdin.readUntilDelimiterOrEof(&line_buf, '\n') catch unreachable) orelse "";
}

View file

@ -1,7 +1,7 @@
{ pkgs }: { pkgs }:
let let
version = "0.8.1"; version = "0.9.1";
osName = if pkgs.stdenv.isDarwin then "macos" else "linux"; osName = if pkgs.stdenv.isDarwin then "macos" else "linux";
@ -14,13 +14,13 @@ let
# If your system is not aarch64, we assume it's x86_64 # If your system is not aarch64, we assume it's x86_64
sha256 = if pkgs.stdenv.isDarwin then sha256 = if pkgs.stdenv.isDarwin then
if isAarch64 then if isAarch64 then
"5351297e3b8408213514b29c0a938002c5cf9f97eee28c2f32920e1227fd8423" # macos-aarch64 "8c473082b4f0f819f1da05de2dbd0c1e891dff7d85d2c12b6ee876887d438287" # macos-aarch64
else else
"16b0e1defe4c1807f2e128f72863124bffdd906cefb21043c34b673bf85cd57f" # macos-x86_64 "2d94984972d67292b55c1eb1c00de46580e9916575d083003546e9a01166754c" # macos-x86_64
else if isAarch64 then else if isAarch64 then
"2166dc9f2d8df387e8b4122883bb979d739281e1ff3f3d5483fec3a23b957510" # linux-aarch64 "5d99a39cded1870a3fa95d4de4ce68ac2610cca440336cfd252ffdddc2b90e66" # linux-aarch64
else else
"6c032fc61b5d77a3f3cf781730fa549f8f059ffdb3b3f6ad1c2994d2b2d87983"; # linux-x86_64 "be8da632c1d3273f766b69244d80669fe4f5e27798654681d77c992f17c237d7"; # linux-x86_64
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
pname = "zig"; pname = "zig";
version = version; version = version;

View file

@ -1,6 +1,6 @@
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use roc_builtins::bitcode; use roc_builtins::bitcode;
@ -10,7 +10,8 @@ const PRE_LINKED_BINARY: &str = "data/pre_linked_binary.o";
fn main() { fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/{}.c", PLATFORM_FILENAME); let source_path = format!("src/{}.c", PLATFORM_FILENAME);
println!("cargo:rerun-if-changed={}", source_path);
// When we build on Netlify, zig is not installed (but also not used, // When we build on Netlify, zig is not installed (but also not used,
// since all we're doing is generating docs), so we can skip the steps // since all we're doing is generating docs), so we can skip the steps
@ -23,26 +24,38 @@ fn main() {
std::fs::create_dir_all("./data").unwrap(); std::fs::create_dir_all("./data").unwrap();
// Build a pre-linked binary with platform, builtins and all their libc dependencies // Zig can produce *either* an object containing relocations OR an object containing libc code
// This builds a library file that exports all symbols. It has no linker data but we don't need it. // But we want both, so we have to compile twice with different flags, then link them
// See discussion with Luuk de Gram (Zig contributor)
// https://github.com/rtfeldman/roc/pull/2181#pullrequestreview-839608063 // Create an object file with relocations
let args = [ let out_dir = env::var("OUT_DIR").unwrap();
"build-lib", let platform_obj = build_wasm_platform(&out_dir, &source_path);
"-target",
"wasm32-wasi", // Compile again to get libc path
"-lc", let (libc_archive, compiler_rt_obj) = build_wasm_libc_compilerrt(&out_dir, &source_path);
"-dynamic", // -dynamic ensures libc code goes into the binary let mut libc_pathbuf = PathBuf::from(&libc_archive);
libc_pathbuf.pop();
let libc_dir = libc_pathbuf.to_str().unwrap();
let args = &[
"wasm-ld",
bitcode::BUILTINS_WASM32_OBJ_PATH, bitcode::BUILTINS_WASM32_OBJ_PATH,
&format!("src/{}.c", PLATFORM_FILENAME), &platform_obj,
&format!("-femit-bin={}", PRE_LINKED_BINARY), &compiler_rt_obj,
"-L",
libc_dir,
"-lc",
"-o",
PRE_LINKED_BINARY,
"--export-all",
"--no-entry",
]; ];
let zig = zig_executable(); let zig = zig_executable();
// println!("{} {}", zig, args.join(" ")); // println!("{} {}", zig, args.join(" "));
run_command(Path::new("."), &zig, args); run_command(&zig, args);
} }
fn zig_executable() -> String { fn zig_executable() -> String {
@ -52,26 +65,77 @@ fn zig_executable() -> String {
} }
} }
fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I) -> String fn build_wasm_platform(out_dir: &str, source_path: &str) -> String {
where let platform_obj = format!("{}/{}.o", out_dir, PLATFORM_FILENAME);
I: IntoIterator<Item = S>,
S: AsRef<OsStr>, run_command(
{ &zig_executable(),
&[
"build-lib",
"-target",
"wasm32-wasi",
"-lc",
source_path,
&format!("-femit-bin={}", &platform_obj),
],
);
platform_obj
}
fn build_wasm_libc_compilerrt(out_dir: &str, source_path: &str) -> (String, String) {
let zig_cache_dir = format!("{}/zig-cache-wasm32", out_dir);
run_command(
&zig_executable(),
&[
"build-lib",
"-dynamic", // ensure libc code is actually generated (not just linked against header)
"-target",
"wasm32-wasi",
"-lc",
source_path,
"-femit-bin=/dev/null",
"--global-cache-dir",
&zig_cache_dir,
],
);
(
run_command("find", &[&zig_cache_dir, "-name", "libc.a"]),
run_command("find", &[&zig_cache_dir, "-name", "compiler_rt.o"]),
)
}
fn run_command(command_str: &str, args: &[&str]) -> String {
let output_result = Command::new(OsStr::new(&command_str)) let output_result = Command::new(OsStr::new(&command_str))
.current_dir(path) .current_dir(Path::new("."))
.args(args) .args(args)
.output(); .output();
let fail = |err: String| {
panic!(
"\n\nFailed command:\n\t{} {}\n\n{}",
command_str,
args.join(" "),
err
);
};
match output_result { match output_result {
Ok(output) => match output.status.success() { Ok(output) => match output.status.success() {
true => std::str::from_utf8(&output.stdout).unwrap().to_string(), true => std::str::from_utf8(&output.stdout)
.unwrap()
.trim()
.to_string(),
false => { false => {
let error_str = match std::str::from_utf8(&output.stderr) { let error_str = match std::str::from_utf8(&output.stderr) {
Ok(stderr) => stderr.to_string(), Ok(stderr) => stderr.to_string(),
Err(_) => format!("Failed to run \"{}\"", command_str), Err(_) => format!("Failed to run \"{}\"", command_str),
}; };
panic!("{} failed: {}", command_str, error_str); fail(error_str)
} }
}, },
Err(reason) => panic!("{} failed: {}", command_str, reason), Err(reason) => fail(reason.to_string()),
} }
} }

View file

@ -36,7 +36,7 @@ let
alsa-lib alsa-lib
]; ];
llvmPkgs = pkgs.llvmPackages_12; llvmPkgs = pkgs.llvmPackages_13;
zig = import ./nix/zig.nix { inherit pkgs; }; zig = import ./nix/zig.nix { inherit pkgs; };
debugir = import ./nix/debugir.nix { inherit pkgs; }; debugir = import ./nix/debugir.nix { inherit pkgs; };
@ -78,7 +78,7 @@ in pkgs.mkShell {
buildInputs = inputs ++ darwinInputs ++ linuxInputs; buildInputs = inputs ++ darwinInputs ++ linuxInputs;
# Additional Env vars # Additional Env vars
LLVM_SYS_120_PREFIX = "${llvmPkgs.llvm.dev}"; LLVM_SYS_130_PREFIX = "${llvmPkgs.llvm.dev}";
NIX_GLIBC_PATH = NIX_GLIBC_PATH =
if pkgs.stdenv.isLinux then "${pkgs.glibc_multi.out}/lib" else ""; if pkgs.stdenv.isLinux then "${pkgs.glibc_multi.out}/lib" else "";
LD_LIBRARY_PATH = with pkgs; LD_LIBRARY_PATH = with pkgs;

View file

@ -23,7 +23,7 @@ edition = "2018"
# commit of TheDan64/inkwell, push a new tag which points to the latest commit, # commit of TheDan64/inkwell, push a new tag which points to the latest commit,
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`. # change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
# This way, GitHub Actions works and nobody's builds get broken. # This way, GitHub Actions works and nobody's builds get broken.
inkwell = { git = "https://github.com/rtfeldman/inkwell", branch = "master", features = [ "llvm12-0" ] } inkwell = { git = "https://github.com/rtfeldman/inkwell", branch = "master", features = [ "llvm13-0" ] }
[features] [features]
target-arm = [] target-arm = []