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
**version: 0.8.0**
**version: 0.9.1**
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.
### LLVM
**version: 12.0.x**
**version: 13.0.x**
For macOS, you can install LLVM 12 using `brew install llvm@12` and then adding
`$(brew --prefix llvm@12)/bin` to your `PATH`. You can confirm this worked by
running `llc --version` - it should mention "LLVM version 12.0.0" at the top.
For macOS, you can install LLVM 13 using `brew install llvm@13` and then adding
`$(brew --prefix llvm@13)/bin` to your `PATH`. You can confirm this worked by
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:
```
export LLVM_SYS_120_PREFIX=/usr/local/opt/llvm@12
export LLVM_SYS_130_PREFIX=/usr/local/opt/llvm@13
```
For Ubuntu and Debian:
@ -153,19 +153,15 @@ For Ubuntu and Debian:
sudo apt -y install lsb-release software-properties-common gnupg
wget https://apt.llvm.org/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`.
By default, the script installs them as `clang-12` and `llvm-as-12`,
respectively. You can address this with symlinks like so:
If you use this script, you'll need to add `clang` to your `PATH`.
By default, the script installs it as `clang-13`. 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

4
Cargo.lock generated
View file

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

View file

@ -17,9 +17,9 @@ install-zig-llvm-valgrind-clippy-rustfmt:
# editor
RUN apt -y install libxkbcommon-dev
# zig
RUN wget -c https://ziglang.org/download/0.8.0/zig-linux-x86_64-0.8.0.tar.xz --no-check-certificate
RUN tar -xf zig-linux-x86_64-0.8.0.tar.xz
RUN ln -s /earthbuild/zig-linux-x86_64-0.8.0/zig /bin/zig
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.9.1.tar.xz
RUN ln -s /earthbuild/zig-linux-x86_64-0.9.1/zig /bin/zig
# zig builtins wasm tests
RUN apt -y install build-essential
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 wget https://apt.llvm.org/llvm.sh
RUN chmod +x llvm.sh
RUN ./llvm.sh 12
RUN ln -s /usr/bin/clang-12 /usr/bin/clang
RUN ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as
RUN ./llvm.sh 13
RUN ln -s /usr/bin/clang-13 /usr/bin/clang
# 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"
# valgrind
RUN apt -y install valgrind

View file

@ -76,9 +76,9 @@ popd
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)
wget -c https://ziglang.org/download/0.7.1/zig-linux-x86_64-0.7.1.tar.xz --no-check-certificate
tar -xf zig-linux-x86_64-0.7.1.tar.xz
ln -s "$PWD/zig-linux-x86_64-0.7.1/zig" /usr/local/bin/zig
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.9.1.tar.xz
ln -s "$PWD/zig-linux-x86_64-0.9.1/zig" /usr/local/bin/zig
# test sccache
./ci/sccache -V

View file

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

View file

@ -1,4 +1,5 @@
const std = @import("std");
const builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
@ -14,7 +15,7 @@ comptime {
// -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
// it everywhere!
if (std.builtin.os.tag == .macos) {
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
@ -22,23 +23,28 @@ comptime {
const mem = std.mem;
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 realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 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);
}
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);
}
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)));
}
@ -50,7 +56,9 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
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 msg = @ptrCast([*:0]const u8, c_ptr);
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
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
const callresult = roc__mainForHost_1_exposed();
var callresult = RocStr.empty();
roc__mainForHost_1_exposed_generic(&callresult);
// end time
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.print("{s}\n", .{callresult.asSlice()}) catch unreachable;

View file

@ -1,4 +1,5 @@
const std = @import("std");
const builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
@ -14,7 +15,7 @@ comptime {
// -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
// it everywhere!
if (std.builtin.os.tag == .macos) {
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
@ -22,23 +23,27 @@ comptime {
const mem = std.mem;
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 realloc(c_ptr: [*]align(@alignOf(u128)) u8, 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) ?*anyopaque;
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 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);
}
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);
}
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)));
}
@ -50,7 +55,9 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
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 msg = @ptrCast([*:0]const u8, c_ptr);
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
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
const callresult = roc__mainForHost_1_exposed();
var callresult = RocStr.empty();
roc__mainForHost_1_exposed_generic(&callresult);
// end time
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.print("{s}\n", .{callresult.asSlice()}) catch unreachable;

332
cli_utils/Cargo.lock generated
View file

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

View file

@ -19,11 +19,6 @@ pub struct CodeGenTiming {
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 {
report_problems_help(
loaded.total_problems(),
@ -357,9 +352,11 @@ pub fn gen_from_mono_module_llvm(
use target_lexicon::Architecture;
match target.architecture {
Architecture::X86_64 | Architecture::X86_32(_) | Architecture::Aarch64(_) => {
// assemble the .ll into a .bc
let _ = Command::new("llvm-as")
Architecture::X86_64
| Architecture::X86_32(_)
| Architecture::Aarch64(_)
| Architecture::Wasm32 => {
let ll_to_bc = Command::new("llvm-as")
.args(&[
app_ll_dbg_file.to_str().unwrap(),
"-o",
@ -368,6 +365,8 @@ pub fn gen_from_mono_module_llvm(
.output()
.unwrap();
assert!(ll_to_bc.stderr.is_empty(), "{:#?}", ll_to_bc);
let llc_args = &[
"-relocation-model=pic",
"-filetype=obj",
@ -381,26 +380,9 @@ pub fn gen_from_mono_module_llvm(
//
// different systems name this executable differently, so we shotgun for
// the most common ones and then give up.
let _: Result<std::process::Output, std::io::Error> =
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);
});
}
let bc_to_object = Command::new("llc").args(llc_args).output().unwrap();
Architecture::Wasm32 => {
// 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();
assert!(bc_to_object.stderr.is_empty(), "{:#?}", bc_to_object);
}
_ => unreachable!(),
}

View file

@ -5,7 +5,7 @@ const CrossTarget = std.zig.CrossTarget;
const Arch = std.Target.Cpu.Arch;
pub fn build(b: *Builder) void {
// b.setPreferredReleaseMode(builtin.Mode.Debug
// b.setPreferredReleaseMode(.Debug);
b.setPreferredReleaseMode(.ReleaseFast);
const mode = b.standardReleaseOptions();
@ -57,8 +57,9 @@ fn generateLlvmIrFile(
const obj = b.addObject(object_name, main_path);
obj.setBuildMode(mode);
obj.strip = true;
obj.emit_llvm_ir = true;
obj.emit_bin = false;
obj.emit_llvm_ir = .emit;
obj.emit_llvm_bc = .emit;
obj.emit_bin = .no_emit;
obj.target = target;
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
# 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)
wasmer $wasm_test_binary dummyArgForZigTestBinary
# Zig will try to run the test binary it produced, but it is a wasm object and hence your OS won't
# 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)
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..];
// 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,
// and then release the lock once we're done modifying things.
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
// 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();
failures_mutex.lock();
defer failures_mutex.unlock();
// If we don't have enough capacity to add a failure, allocate a new failures pointer.
if (failure_length >= failure_capacity) {
@ -87,17 +77,8 @@ pub fn expectFailedC(
}
pub fn getExpectFailures() []Failure {
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
// 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();
failures_mutex.lock();
defer failures_mutex.unlock();
if (failure_length > 0) {
// 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 {
var bytes = @ptrCast(*c_void, failures);
var bytes = @ptrCast(*anyopaque, failures);
return .{ .pointer = bytes, .len = failure_length };
}
pub fn deinitFailures() void {
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
// 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();
failures_mutex.lock();
defer failures_mutex.unlock();
utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure));
failure_length = 0;

View file

@ -1326,7 +1326,6 @@ pub fn listFindUnsafe(
data: Opaque,
inc_n_data: IncN,
data_is_owned: bool,
alignment: u32,
element_width: usize,
inc: Inc,
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),
// so instead we ask Zig to please provide implementations for us, which is does
// (seemingly via musl).
pub usingnamespace @import("std").c.builtins;
pub extern fn setjmp([*c]c_int) c_int;
pub extern fn longjmp([*c]c_int, c_int) noreturn;
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;
if (std.fmt.parseInt(T, buf.asSlice(), radix)) |success| {
return .{ .errorcode = 0, .value = success };
} else |err| {
} else |_| {
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) {
if (std.fmt.parseFloat(T, buf.asSlice())) |success| {
return .{ .errorcode = 0, .value = success };
} else |err| {
} else |_| {
return .{ .errorcode = 1, .value = 0 };
}
}

View file

@ -2041,7 +2041,7 @@ test "ReverseUtf8View: empty" {
const original_bytes = "";
var iter = ReverseUtf8View.initUnchecked(original_bytes).iterator();
while (iter.nextCodepoint()) |codepoint| {
while (iter.nextCodepoint()) |_| {
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!
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.
// 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.
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
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)
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 {
return @ptrCast(?*c_void, std.testing.allocator.alloc(u8, size) catch unreachable);
fn testing_roc_alloc(size: usize, _: u32) callconv(.C) ?*anyopaque {
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 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));
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;
_ = tag_id;
@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_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
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 });
}
@ -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
// 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;
_ = alignment;
// const cstr = @ptrCast([*:0]u8, c_ptr);
@ -240,7 +240,7 @@ pub fn allocateWithRefcount(
}
pub const CSlice = extern struct {
pointer: *c_void,
pointer: *anyopaque,
len: usize,
};

View file

@ -36,30 +36,15 @@ fn main() {
// 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 {
generate_bc_file(
&bitcode_path,
&build_script_dir_path,
"ir-wasm32",
"builtins-wasm32",
);
generate_bc_file(&bitcode_path, "ir-wasm32", "builtins-wasm32");
}
generate_bc_file(
&bitcode_path,
&build_script_dir_path,
"ir-i386",
"builtins-i386",
);
generate_bc_file(&bitcode_path, "ir-i386", "builtins-i386");
generate_bc_file(
&bitcode_path,
&build_script_dir_path,
"ir-x86_64",
"builtins-x86_64",
);
generate_bc_file(&bitcode_path, "ir-x86_64", "builtins-x86_64");
// OBJECT FILES
#[cfg(windows)]
@ -131,35 +116,23 @@ fn generate_object_file(
}
}
fn generate_bc_file(
bitcode_path: &Path,
build_script_dir_path: &Path,
zig_object: &str,
file_name: &str,
) {
fn generate_bc_file(bitcode_path: &Path, zig_object: &str, file_name: &str) {
let mut ll_path = bitcode_path.join(file_name);
ll_path.set_extension("ll");
let dest_ir_host = ll_path.to_str().expect("Invalid dest ir path");
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(
&bitcode_path,
&zig_executable(),
&["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)

View file

@ -68,6 +68,8 @@ use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, Unio
use roc_target::{PtrWidth, TargetInfo};
use target_lexicon::{Architecture, OperatingSystem, Triple};
use super::convert::zig_with_overflow_roc_dec;
#[inline(always)]
fn print_fn_verification_output() -> bool {
dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, {
@ -5246,6 +5248,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
argument_layouts,
Layout::Builtin(Builtin::Bool),
);
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
}
_ => unreachable!("invalid list layout"),
@ -5368,7 +5371,17 @@ fn run_low_level<'a, 'ctx, 'env>(
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 => {
// 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>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
@ -7093,7 +7176,7 @@ fn build_dec_binop<'a, 'ctx, 'env>(
rhs,
"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);
}
@ -7108,15 +7191,7 @@ fn build_dec_binop_throw_on_overflow<'a, 'ctx, 'env>(
rhs: BasicValueEnum<'ctx>,
message: &str,
) -> BasicValueEnum<'ctx> {
let overflow_type = crate::llvm::convert::zig_with_overflow_roc_dec(env);
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 result = dec_binop_with_overflow(env, operation, lhs, rhs);
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.
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 {
// This is guaranteed to succeed so we can just make it an int cast and let LLVM
// optimize it away.
@ -7225,8 +7303,6 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
)
.into();
let return_type =
convert::basic_type_from_layout(env, return_layout).into_struct_type();
let r = return_type.const_zero();
let r = bd
.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]
};
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()
.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_iv = alignment.as_int_value(env.context);
@ -308,17 +310,26 @@ pub fn dict_get<'a, 'ctx, 'env>(
)
.into_struct_value();
let flag = env
let flag_u8 = env
.builder
.build_extract_value(result, 1, "get_flag")
.unwrap()
.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
.builder
.build_extract_value(result, 0, "get_value_ptr")
.unwrap()
.into_pointer_value();
.build_int_to_ptr(value_u8_ptr_int, ptr_type, "opaque_value_ptr");
let start_block = env.builder.get_insert_block().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 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();
env.builder

View file

@ -494,7 +494,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
layout_width(env, element_layout),
layout_width(env, function_call_return_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(),
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())
}
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
pub fn list_keep_oks<'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 {
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
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);
}
_ => unreachable!(),
@ -644,7 +668,7 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
layout_width(env, before_layout),
layout_width(env, result_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(),
],
bitcode::LIST_KEEP_OKS,
@ -692,7 +716,7 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
layout_width(env, before_layout),
layout_width(env, result_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(),
],
bitcode::LIST_KEEP_ERRS,
@ -968,7 +992,6 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
inc_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
// 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
.build_extract_value(result, 0, "get_value_ptr")
.build_extract_value(result, 0, "get_value_ptr_int")
.unwrap()
.into_pointer_value();
.into_int_value();
let found = env
let found_u8 = env
.builder
.build_extract_value(result, 1, "get_found")
.unwrap()
.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 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);
env.builder.position_at_end(if_not_null);
let value_ptr = env
.builder
.build_bitcast(
value_u8_ptr,
let value_ptr = env.builder.build_int_to_ptr(
value_u8_ptr_int,
value_bt.ptr_type(AddressSpace::Generic),
"from_opaque",
)
.into_pointer_value();
"get_value_ptr",
);
let loaded = env.builder.build_load(value_ptr, "load_value");
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::build::{complex_bitcast, Env, Scope};
use crate::llvm::build::{Env, Scope};
use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list};
use inkwell::builder::Builder;
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_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(
env,
&[
list_symbol_to_c_abi(env, scope, list).into(),
complex_bitcast(
env.builder,
count_and_start.into(),
env.twice_ptr_int().into(),
"to_i128",
),
count,
start,
result_ptr.into(),
],
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_list::{list_len, load_list_ptr};
use crate::llvm::build_str::str_equal;
@ -14,7 +13,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_module::symbol::Symbol;
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;
#[derive(Clone, Debug)]
@ -124,7 +123,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
}
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::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::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 => {
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> {
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> {

View file

@ -21,12 +21,11 @@ use crate::storage::{Storage, StoredValue, StoredValueKind};
use crate::wasm_module::linking::{DataSymbol, LinkingSegment, WasmObjectSymbol};
use crate::wasm_module::sections::{DataMode, DataSegment, Limits};
use crate::wasm_module::{
code_builder, CodeBuilder, Export, ExportType, LocalId, Signature, SymInfo, ValueType,
WasmModule,
code_builder, CodeBuilder, ExportType, LocalId, Signature, SymInfo, ValueType, WasmModule,
};
use crate::{
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, MEMORY_NAME,
PTR_SIZE, PTR_TYPE, STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, TARGET_INFO,
copy_memory, round_up_to_alignment, CopyMemoryConfig, Env, DEBUG_LOG_SETTINGS, PTR_SIZE,
PTR_TYPE, TARGET_INFO,
};
#[derive(Clone, Copy, Debug)]
@ -77,22 +76,32 @@ impl<'a> WasmBackend<'a> {
fn_index_offset: u32,
helper_proc_gen: CodeGenHelp<'a>,
) -> Self {
module.export.append(Export {
name: MEMORY_NAME.as_bytes(),
ty: ExportType::Mem,
index: 0,
});
module.export.append(Export {
name: STACK_POINTER_NAME.as_bytes(),
ty: ExportType::Global,
index: STACK_POINTER_GLOBAL_ID,
});
// The preloaded builtins object file exports all functions, but the final app binary doesn't.
// Remove the function exports and use them to populate the Name section (debug info)
let platform_and_builtins_exports =
std::mem::replace(&mut module.export.exports, bumpalo::vec![in env.arena]);
let mut app_exports = Vec::with_capacity_in(32, env.arena);
for ex in platform_and_builtins_exports.into_iter() {
match ex.ty {
ExportType::Func => module.names.append_function(ex.index, ex.name),
_ => app_exports.push(ex),
}
}
// 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!
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);
module.export.exports = app_exports;
WasmBackend {
env,
interns,
@ -224,15 +233,19 @@ impl<'a> WasmBackend<'a> {
}
fn start_proc(&mut self, proc: &Proc<'a>) {
use ReturnMethod::*;
let ret_layout = WasmLayout::new(&proc.ret_layout);
let ret_type = match ret_layout.return_method() {
ReturnMethod::Primitive(ty, _) => Some(ty),
ReturnMethod::NoReturnValue => None,
ReturnMethod::WriteToPointerArg => {
let ret_type = match ret_layout.return_method(CallConv::C) {
Primitive(ty, _) => Some(ty),
NoReturnValue => None,
WriteToPointerArg => {
self.storage.arg_types.push(PTR_TYPE);
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.
@ -323,7 +336,7 @@ impl<'a> WasmBackend<'a> {
};
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::Primitive(ty, size) => {
// 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;
None
}
x => internal_error!("A Roc function should never use ReturnMethod {:?}", x),
};
// Load all the arguments for the inner function
@ -1020,7 +1034,8 @@ impl<'a> WasmBackend<'a> {
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.storage.load_symbols_for_call(
self.env.arena,
&mut self.code_builder,
arguments,
@ -1028,6 +1043,7 @@ impl<'a> WasmBackend<'a> {
&wasm_layout,
CallConv::C,
);
debug_assert!(!ret_zig_packed_struct);
for (roc_proc_index, lookup) in self.proc_lookup.iter().enumerate() {
let ProcLookupData {
@ -1038,8 +1054,6 @@ impl<'a> WasmBackend<'a> {
} = lookup;
if *ir_sym == func_sym && pl == proc_layout {
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(
wasm_fn_index,
*linker_sym_index,

View file

@ -4,9 +4,6 @@ use roc_mono::layout::{Layout, UnionLayout};
use crate::wasm_module::ValueType;
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)]
pub enum ReturnMethod {
/// This layout is returned from a Wasm function "normally" as a Primitive
@ -15,6 +12,8 @@ pub enum ReturnMethod {
WriteToPointerArg,
/// This layout is empty and requires no return value or argument (e.g. refcount helpers)
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)]
@ -124,24 +123,14 @@ impl WasmLayout {
}
}
pub fn return_method(&self) -> ReturnMethod {
pub fn return_method(&self, conv: CallConv) -> ReturnMethod {
match self {
Self::Primitive(ty, size) => ReturnMethod::Primitive(*ty, *size),
Self::StackMemory { size, .. } => {
if *size == 0 {
ReturnMethod::NoReturnValue
} else {
ReturnMethod::WriteToPointerArg
Self::StackMemory { size, format, .. } => {
conv.stack_memory_return_method(*size, *format)
}
}
}
}
}
#[derive(PartialEq, Eq)]
pub enum ZigVersion {
Zig8,
Zig9,
}
#[derive(Debug, Clone, Copy)]
@ -149,8 +138,8 @@ pub enum CallConv {
/// The C calling convention, as defined here:
/// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
C,
/// The calling convention that Zig 0.8 or 0.9 generates for Wasm when we *ask* it
/// for the .C calling convention, due to bugs in both versions of the Zig compiler.
/// The calling convention that Zig 0.9 generates for Wasm when we *ask* it
/// for the .C calling convention, due to bugs in the Zig compiler.
Zig,
}
@ -182,7 +171,7 @@ impl CallConv {
&[I32] // Small struct: pass by value
} else if size <= 8 {
&[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
} else if size <= 16 {
&[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
/// It implements the calling convention used by Zig for both numbers and structs
/// 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.env.arena,
&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) {
let (param_types, ret_type) = self.load_args(backend);
backend.call_zig_builtin_after_loading_args(name, param_types.len(), ret_type.is_some());
let (num_wasm_args, has_return_val, ret_zig_packed_struct) = self.load_args(backend);
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

View file

@ -6,9 +6,7 @@ use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::layout::Layout;
use crate::layout::{
CallConv, ReturnMethod, StackMemoryFormat, WasmLayout, ZigVersion, BUILTINS_ZIG_VERSION,
};
use crate::layout::{CallConv, ReturnMethod, StackMemoryFormat, WasmLayout};
use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
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);
} else if *size <= 8 {
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.get_local(local_id);
code_builder.i32_load(align, offset + 8);
@ -397,37 +395,47 @@ impl<'a> Storage<'a> {
return_symbol: Symbol,
return_layout: &WasmLayout,
call_conv: CallConv,
) -> (Vec<'a, ValueType>, Option<ValueType>) {
let mut wasm_arg_types = Vec::with_capacity_in(arguments.len() * 2 + 1, arena);
let mut wasm_args = Vec::with_capacity_in(arguments.len() * 2 + 1, arena);
) -> (usize, bool, bool) {
use ReturnMethod::*;
let return_method = return_layout.return_method();
let return_type = match return_method {
ReturnMethod::Primitive(ty, _) => Some(ty),
ReturnMethod::NoReturnValue => None,
ReturnMethod::WriteToPointerArg => {
wasm_arg_types.push(PTR_TYPE);
wasm_args.push(return_symbol);
None
let mut num_wasm_args = 0;
let mut symbols_to_load = Vec::with_capacity_in(arguments.len() * 2 + 1, arena);
let return_method = return_layout.return_method(call_conv);
let has_return_val = match return_method {
Primitive(..) => true,
NoReturnValue => false,
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 {
let stored = self.symbol_storage_map.get(arg).unwrap();
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() {
0 => {}
1 => wasm_args.push(*arg),
2 => wasm_args.extend_from_slice(&[*arg, *arg]),
1 => symbols_to_load.push(*arg),
2 => symbols_to_load.extend_from_slice(&[*arg, *arg]),
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!
// Should be common for simple cases, due to the structure of the Mono IR
if !code_builder.verify_stack_match(&wasm_args) {
if return_method == ReturnMethod::WriteToPointerArg {
if !code_builder.verify_stack_match(&symbols_to_load) {
if matches!(return_method, WriteToPointerArg | ZigPackedStruct) {
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

View file

@ -5,7 +5,7 @@ pub mod opcodes;
pub mod sections;
pub mod serialize;
use bumpalo::Bump;
use bumpalo::{collections::Vec, Bump};
pub use code_builder::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
pub use linking::SymInfo;
use roc_error_macros::internal_error;
@ -145,7 +145,7 @@ impl<'a> WasmModule<'a> {
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);
@ -191,10 +191,18 @@ impl<'a> WasmModule<'a> {
arena: &'a Bump,
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(
arena,
self.import.function_count,
&self.export.function_indices,
&function_indices,
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]) {
if module_bytes[*cursor] != id as u8 {
if (*cursor >= module_bytes.len()) || (module_bytes[*cursor] != id as u8) {
return (0, &[]);
}
*cursor += 1;
@ -809,56 +809,35 @@ impl Serialize for Export<'_> {
#[derive(Debug)]
pub struct ExportSection<'a> {
pub count: u32,
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>,
pub exports: Vec<'a, Export<'a>>,
}
impl<'a> ExportSection<'a> {
const ID: SectionId = SectionId::Export;
pub fn append(&mut self, export: Export) {
export.serialize(&mut self.bytes);
self.count += 1;
if matches!(export.ty, ExportType::Func) {
self.function_indices.push(export.index);
}
pub fn append(&mut self, export: Export<'a>) {
self.exports.push(export);
}
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 {
ExportSection {
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 {
/// Preload from object file.
pub fn preload(arena: &'a Bump, module_bytes: &[u8], cursor: &mut usize) -> Self {
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;
for _ in 0..num_exports {
let export_start = body_cursor;
while body_cursor < body_bytes.len() {
let export = Export::parse(arena, body_bytes, &mut body_cursor);
if matches!(export.ty, ExportType::Global) {
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.exports.push(export);
}
export_section
@ -867,10 +846,9 @@ impl<'a> ExportSection<'a> {
impl<'a> Serialize for ExportSection<'a> {
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);
buffer.encode_u32(self.count);
buffer.append_slice(&self.bytes);
self.exports.serialize(buffer);
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 {
// 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
let section_id_byte = module_bytes[*cursor];
if section_id_byte != Self::ID as u8 {

View file

@ -1,7 +1,7 @@
use roc_builtins::bitcode;
use std::env;
use std::ffi::OsStr;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Command;
const PLATFORM_FILENAME: &str = "wasm_test_platform";
@ -15,11 +15,44 @@ fn main() {
}
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);
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 {
@ -29,29 +62,46 @@ fn zig_executable() -> String {
}
}
/// Create an all-in-one object file: platform + builtins + libc
fn build_wasm_platform_and_builtins(out_dir: &str) {
println!("cargo:rerun-if-changed=src/helpers/{}.c", PLATFORM_FILENAME);
fn build_wasm_platform(out_dir: &str, source_path: &str) -> String {
let platform_path = format!("{}/{}.o", out_dir, PLATFORM_FILENAME);
// See discussion with Luuk de Gram (Zig contributor)
// https://github.com/rtfeldman/roc/pull/2181#pullrequestreview-839608063
// This builds a library file that exports everything. It has no linker data but we don't need that.
let args = [
run_command(
&zig_executable(),
&[
"build-lib",
"-target",
"wasm32-wasi",
"-lc",
"-dynamic", // -dynamic ensures libc code goes into the binary
bitcode::BUILTINS_WASM32_OBJ_PATH,
&format!("src/helpers/{}.c", PLATFORM_FILENAME),
&format!("-femit-bin={}/{}.o", out_dir, PLATFORM_FILENAME),
];
source_path,
&format!("-femit-bin={}", &platform_path),
],
);
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 {
@ -62,26 +112,35 @@ fn feature_is_enabled(feature_name: &str) -> bool {
env::var(cargo_env_var).is_ok()
}
fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I) -> String
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
fn run_command(command_str: &str, args: &[&str]) -> String {
let output_result = Command::new(OsStr::new(&command_str))
.current_dir(path)
.current_dir(Path::new("."))
.args(args)
.output();
let fail = |err: String| {
panic!(
"\n\nFailed command:\n\t{} {}\n\n{}",
command_str,
args.join(" "),
err
);
};
match output_result {
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 => {
let error_str = match std::str::from_utf8(&output.stderr) {
Ok(stderr) => stderr.to_string(),
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 <stdlib.h>
#include <string.h>
// Makes test runs take 50% longer, due to linking
#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 expectEqual = testing.expectEqual;
const expect = testing.expect;
const maxInt = std.math.maxInt;
comptime {
// 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
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @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;
const Align = extern struct { a: usize, b: usize };
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
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) {
var ptr = malloc(size);
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) {
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(@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) {
const stdout = std.io.getStdOut().writer();
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;
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);
}
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 {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
// start time
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);
// end time
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;

View file

@ -1,4 +1,7 @@
const std = @import("std");
const builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
@ -12,7 +15,7 @@ comptime {
// -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
// it everywhere!
if (std.builtin.os.tag == .macos) {
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
@ -21,18 +24,17 @@ const mem = std.mem;
const Allocator = mem.Allocator;
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 };
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
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) {
var ptr = malloc(size);
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) {
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(@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) {
const stdout = std.io.getStdOut().writer();
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;
const stderr = std.io.getStdErr().writer();
@ -87,7 +89,6 @@ const Unit = extern struct {};
pub export fn main() u8 {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
var raw_numbers: [NUM_NUMS + 1]i64 = undefined;
@ -104,7 +105,7 @@ pub export fn main() u8 {
// start time
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
var callresult: RocList = undefined;
@ -118,7 +119,7 @@ pub export fn main() u8 {
// end time
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| {
if (i == 0) {

View file

@ -15,7 +15,8 @@ comptime {
// -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
// it everywhere!
if (std.builtin.os.tag == .macos) {
const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
@ -30,15 +31,15 @@ extern fn roc__mainForHost_1_Fx_size() i64;
extern fn roc__mainForHost_1_Fx_result_size() i64;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void;
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
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) {
var ptr = malloc(size);
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) {
const stdout = std.io.getStdOut().writer();
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);
}
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) {
const stdout = std.io.getStdOut().writer();
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)));
}
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();
@ -98,7 +99,7 @@ pub export fn main() callconv(.C) u8 {
}
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);
@ -107,7 +108,7 @@ pub export fn main() callconv(.C) u8 {
call_the_closure(closure_data_pointer);
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);
@ -214,8 +215,3 @@ fn roc_fx_getInt_help() !i64 {
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 builtin = @import("builtin");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
@ -14,21 +15,21 @@ comptime {
// -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
// it everywhere!
if (std.builtin.os.tag == .macos) {
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void;
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
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) {
var ptr = malloc(size);
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) {
const stdout = std.io.getStdOut().writer();
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);
}
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) {
const stdout = std.io.getStdOut().writer();
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)));
}
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();
@ -87,7 +88,7 @@ pub fn main() u8 {
// start time
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
var callresult = RocStr.empty();
@ -95,7 +96,7 @@ pub fn main() u8 {
// end time
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.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
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @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_result_size() i64;
extern fn malloc(size: usize) callconv(.C) ?*c_void;
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 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;
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 {
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
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 {
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
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 msg = @ptrCast([*:0]const u8, c_ptr);
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 {
const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
// 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;
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);
call_the_closure(output);
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);
@ -130,11 +152,7 @@ fn call_the_closure(closure_data_pointer: [*]u8) void {
}
pub export fn roc_fx_getLine() str.RocStr {
if (roc_fx_getLine_help()) |value| {
return value;
} else |err| {
return str.RocStr.empty();
}
return roc_fx_getLine_help() catch return str.RocStr.empty();
}
fn roc_fx_getLine_help() !RocStr {
@ -188,8 +206,3 @@ fn roc_fx_getInt_help() !i64 {
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
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
const builtin = @import("builtin");
if (builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
@ -79,15 +80,15 @@ fn view(input: ConstModel) RocStr {
}
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void;
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
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 memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
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) {
var ptr = malloc(size);
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) {
const stdout = std.io.getStdOut().writer();
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);
}
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) {
const stdout = std.io.getStdOut().writer();
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)));
}
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();
@ -136,17 +137,15 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
const Unit = extern struct {};
pub export fn main() callconv(.C) u8 {
const allocator = std.heap.page_allocator;
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();
call_the_closure(program);
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);
@ -161,13 +160,15 @@ fn to_seconds(tms: std.os.timespec) f64 {
}
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 stdin = std.io.getStdIn().reader();
var buf: [1000]u8 = undefined;
var model = init(allocator);
var model = init(&allocator);
while (true) {
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);
model = update(allocator, model, to_append);
model = update(&allocator, model, to_append);
const viewed = view(model);
for (viewed.asSlice()) |char| {
@ -266,8 +267,3 @@ fn roc_fx_getInt_help() !i64 {
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 }:
let
version = "0.8.1";
version = "0.9.1";
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
sha256 = if pkgs.stdenv.isDarwin then
if isAarch64 then
"5351297e3b8408213514b29c0a938002c5cf9f97eee28c2f32920e1227fd8423" # macos-aarch64
"8c473082b4f0f819f1da05de2dbd0c1e891dff7d85d2c12b6ee876887d438287" # macos-aarch64
else
"16b0e1defe4c1807f2e128f72863124bffdd906cefb21043c34b673bf85cd57f" # macos-x86_64
"2d94984972d67292b55c1eb1c00de46580e9916575d083003546e9a01166754c" # macos-x86_64
else if isAarch64 then
"2166dc9f2d8df387e8b4122883bb979d739281e1ff3f3d5483fec3a23b957510" # linux-aarch64
"5d99a39cded1870a3fa95d4de4ce68ac2610cca440336cfd252ffdddc2b90e66" # linux-aarch64
else
"6c032fc61b5d77a3f3cf781730fa549f8f059ffdb3b3f6ad1c2994d2b2d87983"; # linux-x86_64
"be8da632c1d3273f766b69244d80669fe4f5e27798654681d77c992f17c237d7"; # linux-x86_64
in pkgs.stdenv.mkDerivation {
pname = "zig";
version = version;

View file

@ -1,6 +1,6 @@
use std::env;
use std::ffi::OsStr;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::Command;
use roc_builtins::bitcode;
@ -10,7 +10,8 @@ const PRE_LINKED_BINARY: &str = "data/pre_linked_binary.o";
fn main() {
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,
// 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();
// Build a pre-linked binary with platform, builtins and all their libc dependencies
// This builds a library file that exports all symbols. It has no linker data but we don't need it.
// See discussion with Luuk de Gram (Zig contributor)
// https://github.com/rtfeldman/roc/pull/2181#pullrequestreview-839608063
let args = [
"build-lib",
"-target",
"wasm32-wasi",
"-lc",
"-dynamic", // -dynamic ensures libc code goes into the binary
// 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 out_dir = env::var("OUT_DIR").unwrap();
let platform_obj = build_wasm_platform(&out_dir, &source_path);
// Compile again to get libc path
let (libc_archive, compiler_rt_obj) = build_wasm_libc_compilerrt(&out_dir, &source_path);
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,
&format!("src/{}.c", PLATFORM_FILENAME),
&format!("-femit-bin={}", PRE_LINKED_BINARY),
&platform_obj,
&compiler_rt_obj,
"-L",
libc_dir,
"-lc",
"-o",
PRE_LINKED_BINARY,
"--export-all",
"--no-entry",
];
let zig = zig_executable();
// println!("{} {}", zig, args.join(" "));
run_command(Path::new("."), &zig, args);
run_command(&zig, args);
}
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
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
fn build_wasm_platform(out_dir: &str, source_path: &str) -> String {
let platform_obj = format!("{}/{}.o", out_dir, PLATFORM_FILENAME);
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))
.current_dir(path)
.current_dir(Path::new("."))
.args(args)
.output();
let fail = |err: String| {
panic!(
"\n\nFailed command:\n\t{} {}\n\n{}",
command_str,
args.join(" "),
err
);
};
match output_result {
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 => {
let error_str = match std::str::from_utf8(&output.stderr) {
Ok(stderr) => stderr.to_string(),
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
];
llvmPkgs = pkgs.llvmPackages_12;
llvmPkgs = pkgs.llvmPackages_13;
zig = import ./nix/zig.nix { inherit pkgs; };
debugir = import ./nix/debugir.nix { inherit pkgs; };
@ -78,7 +78,7 @@ in pkgs.mkShell {
buildInputs = inputs ++ darwinInputs ++ linuxInputs;
# Additional Env vars
LLVM_SYS_120_PREFIX = "${llvmPkgs.llvm.dev}";
LLVM_SYS_130_PREFIX = "${llvmPkgs.llvm.dev}";
NIX_GLIBC_PATH =
if pkgs.stdenv.isLinux then "${pkgs.glibc_multi.out}/lib" else "";
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,
# 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.
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]
target-arm = []