mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge remote-tracking branch 'origin/trunk' into name-functions-with-morphic
This commit is contained in:
commit
bb25746928
20 changed files with 484 additions and 181 deletions
23
.github/workflows/benchmarks.yml
vendored
23
.github/workflows/benchmarks.yml
vendored
|
@ -15,10 +15,29 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
|
ref: "trunk"
|
||||||
clean: "true"
|
clean: "true"
|
||||||
|
|
||||||
- name: Earthly version
|
- name: Earthly version
|
||||||
run: earthly --version
|
run: earthly --version
|
||||||
|
|
||||||
- name: install dependencies, build, cd cli, benchmark with criterion
|
- name: on trunk; prepare a self-contained benchmark folder
|
||||||
run: ./ci/safe-earthly.sh +bench-roc
|
run: ./ci/safe-earthly.sh --build-arg BENCH_SUFFIX=trunk +prep-bench-folder
|
||||||
|
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
clean: "false" # we want to keep the benchmark folder
|
||||||
|
|
||||||
|
- name: on current branch; prepare a self-contained benchmark folder
|
||||||
|
run: ./ci/safe-earthly.sh +prep-bench-folder
|
||||||
|
|
||||||
|
- name: benchmark trunk
|
||||||
|
run: ulimit -s unlimited && cd bench-folder-trunk && ./target/release/deps/time_bench --bench
|
||||||
|
# ulimit to prevent stack overflow on cfold
|
||||||
|
|
||||||
|
- name: move benchmark results so they can be compared later
|
||||||
|
run: cp -r bench-folder-trunk/target/criterion bench-folder-branch/target/
|
||||||
|
|
||||||
|
- name: benchmark current branch
|
||||||
|
run: ulimit -s unlimited && cd bench-folder-branch && ./target/release/deps/time_bench --bench
|
||||||
|
# ulimit to prevent stack overflow on cfold
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -27,3 +27,5 @@ editor/benches/resources/500_lines.roc
|
||||||
# rust cache (sccache folder)
|
# rust cache (sccache folder)
|
||||||
sccache_dir
|
sccache_dir
|
||||||
|
|
||||||
|
# self-contained benchmark folder
|
||||||
|
bench-folder*
|
||||||
|
|
|
@ -76,6 +76,8 @@ sudo ln -s /usr/bin/llvm-as-12 /usr/bin/llvm-as
|
||||||
|
|
||||||
There are also alternative installation options at http://releases.llvm.org/download.html
|
There are also alternative installation options at http://releases.llvm.org/download.html
|
||||||
|
|
||||||
|
[Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
## Using Nix
|
## Using Nix
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
@ -154,6 +156,13 @@ On Ubuntu, running `sudo apt install pkg-config cmake libx11-dev` fixed this.
|
||||||
|
|
||||||
If you encounter `cannot find -lz` run `sudo apt install zlib1g-dev`.
|
If you encounter `cannot find -lz` run `sudo apt install zlib1g-dev`.
|
||||||
|
|
||||||
|
If you encounter:
|
||||||
|
```
|
||||||
|
error: No suitable version of LLVM was found system-wide or pointed
|
||||||
|
to by LLVM_SYS_120_PREFIX.
|
||||||
|
```
|
||||||
|
Add `export LLVM_SYS_120_PREFIX=/usr/lib/llvm-12` to your `~/.bashrc` or equivalent file for your shell.
|
||||||
|
|
||||||
### LLVM installation on macOS
|
### LLVM installation on macOS
|
||||||
|
|
||||||
If installing LLVM fails, it might help to run `sudo xcode-select -r` before installing again.
|
If installing LLVM fails, it might help to run `sudo xcode-select -r` before installing again.
|
||||||
|
|
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -1618,13 +1618,13 @@ dependencies = [
|
||||||
name = "inkwell"
|
name = "inkwell"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release4)",
|
"inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release5)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inkwell"
|
name = "inkwell"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release4#8d7174fc8da4d2e6f2555f9ec2b3f7464ec5026b"
|
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release5#b5aa51313d4cfa4e1b52ad630cb786140671478b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"inkwell_internals",
|
"inkwell_internals",
|
||||||
|
@ -1638,7 +1638,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inkwell_internals"
|
name = "inkwell_internals"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release4#8d7174fc8da4d2e6f2555f9ec2b3f7464ec5026b"
|
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release5#b5aa51313d4cfa4e1b52ad630cb786140671478b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
|
@ -3212,7 +3212,6 @@ name = "roc_gen_llvm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"either",
|
|
||||||
"im 14.3.0",
|
"im 14.3.0",
|
||||||
"im-rc 14.3.0",
|
"im-rc 14.3.0",
|
||||||
"indoc 0.3.6",
|
"indoc 0.3.6",
|
||||||
|
|
|
@ -30,7 +30,7 @@ members = [
|
||||||
"cli",
|
"cli",
|
||||||
"cli/cli_utils",
|
"cli/cli_utils",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"docs"
|
"docs",
|
||||||
]
|
]
|
||||||
# Needed to be able to run `cargo run -p roc_cli --no-default-features` -
|
# Needed to be able to run `cargo run -p roc_cli --no-default-features` -
|
||||||
# see www/build.sh for more.
|
# see www/build.sh for more.
|
||||||
|
|
22
Earthfile
22
Earthfile
|
@ -102,7 +102,7 @@ check-rustfmt:
|
||||||
|
|
||||||
check-typos:
|
check-typos:
|
||||||
RUN cargo install typos-cli --version 1.0.4 # use latest version on resolution of issue crate-ci/typos#277
|
RUN cargo install typos-cli --version 1.0.4 # use latest version on resolution of issue crate-ci/typos#277
|
||||||
COPY --dir .github ci cli compiler docs editor examples packages roc_std www *.md LEGAL_DETAILS shell.nix ./
|
COPY --dir .github ci cli compiler docs editor examples nightly_benches packages roc_std www *.md LEGAL_DETAILS shell.nix ./
|
||||||
RUN typos
|
RUN typos
|
||||||
|
|
||||||
test-rust:
|
test-rust:
|
||||||
|
@ -130,11 +130,19 @@ test-all:
|
||||||
BUILD +test-rust
|
BUILD +test-rust
|
||||||
BUILD +verify-no-git-changes
|
BUILD +verify-no-git-changes
|
||||||
|
|
||||||
bench-roc:
|
# compile everything needed for benchmarks and output a self-contained folder
|
||||||
|
prep-bench-folder:
|
||||||
FROM +copy-dirs-and-cache
|
FROM +copy-dirs-and-cache
|
||||||
ENV RUST_BACKTRACE=full
|
ARG BENCH_SUFFIX=branch
|
||||||
RUN cargo criterion -V
|
RUN cargo criterion -V
|
||||||
# ulimit -s unlimited to prevent stack overflow errors for CFold
|
RUN --mount=type=cache,target=$SCCACHE_DIR cd cli && cargo criterion --no-run
|
||||||
RUN --privileged --mount=type=cache,target=$SCCACHE_DIR \
|
RUN mkdir -p bench-folder/compiler/builtins/bitcode/src
|
||||||
ulimit -s unlimited && cd cli && cargo criterion && sccache --show-stats
|
RUN mkdir -p bench-folder/target/release/deps
|
||||||
|
RUN mkdir -p bench-folder/examples/benchmarks
|
||||||
|
RUN cp examples/benchmarks/*.roc bench-folder/examples/benchmarks/
|
||||||
|
RUN cp -r examples/benchmarks/platform bench-folder/examples/benchmarks/
|
||||||
|
RUN cp compiler/builtins/bitcode/src/str.zig bench-folder/compiler/builtins/bitcode/src
|
||||||
|
RUN cp target/release/roc bench-folder/target/release
|
||||||
|
# copy the most recent time bench to bench-folder
|
||||||
|
RUN cp target/release/deps/`ls -t target/release/deps/ | grep time_bench | head -n 1` bench-folder/target/release/deps/time_bench
|
||||||
|
SAVE ARTIFACT bench-folder AS LOCAL bench-folder-$BENCH_SUFFIX
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
LOG_FILE="earthly_log.txt"
|
LOG_FILE="earthly_log.txt"
|
||||||
touch $LOG_FILE
|
touch $LOG_FILE
|
||||||
|
|
||||||
ARGS=$1
|
# first arg + everything after
|
||||||
|
ARGS=${@:1}
|
||||||
if [[ $ARGS == *"bench"* ]]; then
|
FULL_CMD="earthly --config ci/earthly-conf.yml $ARGS"
|
||||||
ARGS="--allow-privileged $ARGS"
|
echo $FULL_CMD
|
||||||
fi
|
script -efq $LOG_FILE -c "$FULL_CMD"
|
||||||
|
|
||||||
script -efq $LOG_FILE -c "earthly --config ci/earthly-conf.yml $ARGS"
|
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
|
|
||||||
if grep -q "failed to mount" "$LOG_FILE"; then
|
if grep -q "failed to mount" "$LOG_FILE"; then
|
||||||
|
|
|
@ -81,15 +81,8 @@ serial_test = "0.5"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
criterion = { git = "https://github.com/Anton-4/criterion.rs"}
|
criterion = { git = "https://github.com/Anton-4/criterion.rs"}
|
||||||
cli_utils = { path = "cli_utils" }
|
cli_utils = { path = "cli_utils" }
|
||||||
# Keep the commented deps, they are commented because they require nightly rust
|
|
||||||
# criterion-perf-events = "0.1.3"
|
|
||||||
# perfcnt = "0.7.1"
|
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "time_bench"
|
name = "time_bench"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
# Keep this benchmark, it's commented because it requires nightly
|
|
||||||
# [[bench]]
|
|
||||||
# name = "events_bench"
|
|
||||||
# harness = false
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ use criterion::{
|
||||||
|
|
||||||
fn bench_group_wall_time(c: &mut Criterion) {
|
fn bench_group_wall_time(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("bench-group_wall-time");
|
let mut group = c.benchmark_group("bench-group_wall-time");
|
||||||
// calculate statistics based on a fixed(flat) 200 runs
|
// calculate statistics based on a fixed(flat) 300 runs
|
||||||
group.sampling_mode(SamplingMode::Flat);
|
group.sampling_mode(SamplingMode::Flat);
|
||||||
group.sample_size(200);
|
group.sample_size(300);
|
||||||
|
|
||||||
let bench_funcs: Vec<fn(Option<&mut BenchmarkGroup<WallTime>>) -> ()> = vec![
|
let bench_funcs: Vec<fn(Option<&mut BenchmarkGroup<WallTime>>) -> ()> = vec![
|
||||||
bench_nqueens, // queens 11
|
bench_nqueens, // queens 11
|
||||||
|
|
|
@ -100,7 +100,7 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if cfg!(feature = "edit") {
|
if cfg!(feature = "editor") {
|
||||||
app.subcommand(
|
app.subcommand(
|
||||||
App::new(CMD_EDIT).about("Launch the Roc editor").arg(
|
App::new(CMD_EDIT).about("Launch the Roc editor").arg(
|
||||||
Arg::with_name(DIRECTORY_OR_FILES)
|
Arg::with_name(DIRECTORY_OR_FILES)
|
||||||
|
|
|
@ -8,6 +8,8 @@ pub const RocDec = struct {
|
||||||
num: i128,
|
num: i128,
|
||||||
|
|
||||||
pub const decimal_places: comptime u32 = 18;
|
pub const decimal_places: comptime u32 = 18;
|
||||||
|
pub const whole_number_places: comptime u32 = 21;
|
||||||
|
const max_digits: comptime u32 = decimal_places + whole_number_places;
|
||||||
|
|
||||||
pub const min: comptime RocDec = .{ .num = math.minInt(i128) };
|
pub const min: comptime RocDec = .{ .num = math.minInt(i128) };
|
||||||
pub const max: comptime RocDec = .{ .num = math.maxInt(i128) };
|
pub const max: comptime RocDec = .{ .num = math.maxInt(i128) };
|
||||||
|
@ -19,7 +21,7 @@ pub const RocDec = struct {
|
||||||
return .{ .num = num * one_point_zero_i128 };
|
return .{ .num = num * one_point_zero_i128 };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromString(roc_str: RocStr) ?RocDec {
|
pub fn fromStr(roc_str: RocStr) ?RocDec {
|
||||||
if (roc_str.isEmpty()) {
|
if (roc_str.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -101,6 +103,7 @@ pub const RocDec = struct {
|
||||||
return dec;
|
return dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Replace this with https://github.com/rtfeldman/roc/pull/1365/files#r643580738
|
||||||
fn isDigit(c: u8) bool {
|
fn isDigit(c: u8) bool {
|
||||||
return switch (c) {
|
return switch (c) {
|
||||||
'0'...'9' => true,
|
'0'...'9' => true,
|
||||||
|
@ -108,6 +111,92 @@ pub const RocDec = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toStr(self: RocDec) ?RocStr {
|
||||||
|
// Check if this Dec is negative, and if so convert to positive
|
||||||
|
// We will handle adding the '-' later
|
||||||
|
const is_negative = self.num < 0;
|
||||||
|
const num = if (is_negative) std.math.negate(self.num) catch {
|
||||||
|
std.debug.panic("TODO runtime exception failing to negate", .{});
|
||||||
|
} else self.num;
|
||||||
|
|
||||||
|
// Format the backing i128 into an array of digits (u8s)
|
||||||
|
var digit_bytes: [max_digits + 1]u8 = undefined;
|
||||||
|
var num_digits_formatted = std.fmt.formatIntBuf(digit_bytes[0..], num, 10, false, .{});
|
||||||
|
|
||||||
|
// If self < 1, then pad digit_bytes with '0' to be at least 18 digits
|
||||||
|
if (num_digits_formatted < decimal_places) {
|
||||||
|
var diff = decimal_places - num_digits_formatted;
|
||||||
|
var padded_digit_bytes: [max_digits + 1]u8 = undefined;
|
||||||
|
var index: usize = 0;
|
||||||
|
|
||||||
|
while (index < decimal_places) {
|
||||||
|
if (index < diff) {
|
||||||
|
padded_digit_bytes[index] = '0';
|
||||||
|
} else {
|
||||||
|
padded_digit_bytes[index] = digit_bytes[index - diff];
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
num_digits_formatted = num_digits_formatted + diff;
|
||||||
|
digit_bytes = padded_digit_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the slice of the part before the decimal
|
||||||
|
// If this is empty, then hardcode a '0'
|
||||||
|
var before_digits_num_raw: usize = undefined;
|
||||||
|
var before_digits_slice: []const u8 = undefined;
|
||||||
|
if (num_digits_formatted > decimal_places) {
|
||||||
|
before_digits_num_raw = num_digits_formatted - decimal_places;
|
||||||
|
before_digits_slice = digit_bytes[0..before_digits_num_raw];
|
||||||
|
} else {
|
||||||
|
before_digits_num_raw = 0;
|
||||||
|
before_digits_slice = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out the index where the trailing zeros start
|
||||||
|
var index = decimal_places - 1;
|
||||||
|
var trim_index: ?usize = null;
|
||||||
|
var is_consecutive_zero = true;
|
||||||
|
while (index != 0) {
|
||||||
|
var digit = digit_bytes[before_digits_num_raw + index];
|
||||||
|
// 48 => '0', 170 => ''
|
||||||
|
if ((digit == 48 or digit == 170) and is_consecutive_zero) {
|
||||||
|
trim_index = index;
|
||||||
|
} else {
|
||||||
|
is_consecutive_zero = false;
|
||||||
|
}
|
||||||
|
index -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the slice of the part afterthe decimal
|
||||||
|
var after_digits_slice: []const u8 = undefined;
|
||||||
|
after_digits_slice = digit_bytes[before_digits_num_raw..(before_digits_num_raw + if (trim_index) |i| i else decimal_places)];
|
||||||
|
|
||||||
|
// Make the RocStr
|
||||||
|
|
||||||
|
var sign_len: usize = if (is_negative) 1 else 0;
|
||||||
|
var dot_len: usize = 1;
|
||||||
|
var str_len: usize = sign_len + before_digits_slice.len + dot_len + after_digits_slice.len;
|
||||||
|
|
||||||
|
// TODO: Ideally we'd use [str_len]u8 here, but Zig gives an error if we do that.
|
||||||
|
// [max_digits + 2]u8 here to account for '.' and '-', aka the max possible length of the string
|
||||||
|
var str_bytes: [max_digits + 2]u8 = undefined;
|
||||||
|
|
||||||
|
// Join the whole number slice & the decimal slice together
|
||||||
|
// The format template arg in bufPrint is `comptime`, so we have to repeate the whole statement in each branch
|
||||||
|
if (is_negative) {
|
||||||
|
_ = std.fmt.bufPrint(str_bytes[0 .. str_len + 1], "-{s}.{s}", .{ before_digits_slice, after_digits_slice }) catch {
|
||||||
|
std.debug.panic("TODO runtime exception failing to print slices", .{});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_ = std.fmt.bufPrint(str_bytes[0 .. str_len + 1], "{s}.{s}", .{ before_digits_slice, after_digits_slice }) catch {
|
||||||
|
std.debug.panic("TODO runtime exception failing to print slices", .{});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return RocStr.init(&str_bytes, str_len);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn negate(self: RocDec) ?RocDec {
|
pub fn negate(self: RocDec) ?RocDec {
|
||||||
var negated = math.negate(self.num) catch null;
|
var negated = math.negate(self.num) catch null;
|
||||||
return if (negated) |n| .{ .num = n } else null;
|
return if (negated) |n| .{ .num = n } else null;
|
||||||
|
@ -319,6 +408,8 @@ fn mul_u128(a: u128, b: u128) U256 {
|
||||||
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const expectEqual = testing.expectEqual;
|
const expectEqual = testing.expectEqual;
|
||||||
|
const expectEqualSlices = testing.expectEqualSlices;
|
||||||
|
const expect = testing.expect;
|
||||||
|
|
||||||
test "fromU64" {
|
test "fromU64" {
|
||||||
var dec = RocDec.fromU64(25);
|
var dec = RocDec.fromU64(25);
|
||||||
|
@ -326,111 +417,229 @@ test "fromU64" {
|
||||||
try expectEqual(RocDec{ .num = 25000000000000000000 }, dec);
|
try expectEqual(RocDec{ .num = 25000000000000000000 }, dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: empty" {
|
test "fromStr: empty" {
|
||||||
var roc_str = RocStr.init("", 0);
|
var roc_str = RocStr.init("", 0);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(dec, null);
|
try expectEqual(dec, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 0" {
|
test "fromStr: 0" {
|
||||||
var roc_str = RocStr.init("0", 1);
|
var roc_str = RocStr.init("0", 1);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = 0 }, dec.?);
|
try expectEqual(RocDec{ .num = 0 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 1" {
|
test "fromStr: 1" {
|
||||||
var roc_str = RocStr.init("1", 1);
|
var roc_str = RocStr.init("1", 1);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec.one_point_zero, dec.?);
|
try expectEqual(RocDec.one_point_zero, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 123.45" {
|
test "fromStr: 123.45" {
|
||||||
var roc_str = RocStr.init("123.45", 6);
|
var roc_str = RocStr.init("123.45", 6);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = 123450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = 123450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: .45" {
|
test "fromStr: .45" {
|
||||||
var roc_str = RocStr.init(".45", 3);
|
var roc_str = RocStr.init(".45", 3);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = 450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = 450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 0.45" {
|
test "fromStr: 0.45" {
|
||||||
var roc_str = RocStr.init("0.45", 4);
|
var roc_str = RocStr.init("0.45", 4);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = 450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = 450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 123" {
|
test "fromStr: 123" {
|
||||||
var roc_str = RocStr.init("123", 3);
|
var roc_str = RocStr.init("123", 3);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = 123000000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = 123000000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: -.45" {
|
test "fromStr: -.45" {
|
||||||
var roc_str = RocStr.init("-.45", 4);
|
var roc_str = RocStr.init("-.45", 4);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = -450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = -450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: -0.45" {
|
test "fromStr: -0.45" {
|
||||||
var roc_str = RocStr.init("-0.45", 5);
|
var roc_str = RocStr.init("-0.45", 5);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = -450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = -450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: -123" {
|
test "fromStr: -123" {
|
||||||
var roc_str = RocStr.init("-123", 4);
|
var roc_str = RocStr.init("-123", 4);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = -123000000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = -123000000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: -123.45" {
|
test "fromStr: -123.45" {
|
||||||
var roc_str = RocStr.init("-123.45", 7);
|
var roc_str = RocStr.init("-123.45", 7);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(RocDec{ .num = -123450000000000000000 }, dec.?);
|
try expectEqual(RocDec{ .num = -123450000000000000000 }, dec.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: abc" {
|
test "fromStr: abc" {
|
||||||
var roc_str = RocStr.init("abc", 3);
|
var roc_str = RocStr.init("abc", 3);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(dec, null);
|
try expectEqual(dec, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: 123.abc" {
|
test "fromStr: 123.abc" {
|
||||||
var roc_str = RocStr.init("123.abc", 7);
|
var roc_str = RocStr.init("123.abc", 7);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(dec, null);
|
try expectEqual(dec, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: abc.123" {
|
test "fromStr: abc.123" {
|
||||||
var roc_str = RocStr.init("abc.123", 7);
|
var roc_str = RocStr.init("abc.123", 7);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(dec, null);
|
try expectEqual(dec, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fromString: .123.1" {
|
test "fromStr: .123.1" {
|
||||||
var roc_str = RocStr.init(".123.1", 6);
|
var roc_str = RocStr.init(".123.1", 6);
|
||||||
var dec = RocDec.fromString(roc_str);
|
var dec = RocDec.fromStr(roc_str);
|
||||||
|
|
||||||
try expectEqual(dec, null);
|
try expectEqual(dec, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "toStr: 123.45" {
|
||||||
|
var dec: RocDec = .{ .num = 123450000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "123.45"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: -123.45" {
|
||||||
|
var dec: RocDec = .{ .num = -123450000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "-123.45"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 123.0" {
|
||||||
|
var dec: RocDec = .{ .num = 123000000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "123.0"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: -123.0" {
|
||||||
|
var dec: RocDec = .{ .num = -123000000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "-123.0"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 0.45" {
|
||||||
|
var dec: RocDec = .{ .num = 450000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "0.45"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: -0.45" {
|
||||||
|
var dec: RocDec = .{ .num = -450000000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "-0.45"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 0.00045" {
|
||||||
|
var dec: RocDec = .{ .num = 000450000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "0.00045"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: -0.00045" {
|
||||||
|
var dec: RocDec = .{ .num = -000450000000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "-0.00045"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: -111.123456789" {
|
||||||
|
var dec: RocDec = .{ .num = -111123456789000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "-111.123456789"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 123.1111111" {
|
||||||
|
var dec: RocDec = .{ .num = 123111111100000000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "123.1111111"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 123.1111111111111 (big str)" {
|
||||||
|
var dec: RocDec = .{ .num = 123111111111111000000 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
errdefer res_roc_str.?.deinit();
|
||||||
|
defer res_roc_str.?.deinit();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "123.111111111111"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 123.111111111111444444 (max number of decimal places)" {
|
||||||
|
var dec: RocDec = .{ .num = 123111111111111444444 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
errdefer res_roc_str.?.deinit();
|
||||||
|
defer res_roc_str.?.deinit();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "123.111111111111444444"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 12345678912345678912.111111111111111111 (max number of digits)" {
|
||||||
|
var dec: RocDec = .{ .num = 12345678912345678912111111111111111111 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
errdefer res_roc_str.?.deinit();
|
||||||
|
defer res_roc_str.?.deinit();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "12345678912345678912.111111111111111111"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "toStr: 0" {
|
||||||
|
var dec: RocDec = .{ .num = 0 };
|
||||||
|
var res_roc_str = dec.toStr();
|
||||||
|
|
||||||
|
const res_slice: []const u8 = "0.0"[0..];
|
||||||
|
try expectEqualSlices(u8, res_slice, res_roc_str.?.asSlice());
|
||||||
|
}
|
||||||
|
|
||||||
test "add: 0" {
|
test "add: 0" {
|
||||||
var dec: RocDec = .{ .num = 0 };
|
var dec: RocDec = .{ .num = 0 };
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ im = "14" # im and im-rc should always have the same version!
|
||||||
im-rc = "14" # im and im-rc should always have the same version!
|
im-rc = "14" # im and im-rc should always have the same version!
|
||||||
bumpalo = { version = "3.6.1", features = ["collections"] }
|
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
inlinable_string = "0.1"
|
inlinable_string = "0.1"
|
||||||
either = "1.6.1"
|
|
||||||
inkwell = { path = "../../vendor/inkwell" }
|
inkwell = { path = "../../vendor/inkwell" }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.10"
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,9 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
&(bumpalo::vec![ in env.arena; BasicTypeEnum::PointerType(arg_type); argument_layouts.len() + 2 ]),
|
&(bumpalo::vec![ in env.arena; BasicTypeEnum::PointerType(arg_type); argument_layouts.len() + 2 ]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// called from zig, must use C calling convention
|
||||||
|
function_value.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
||||||
debug_assert!(kind_id > 0);
|
debug_assert!(kind_id > 0);
|
||||||
let attr = env.context.create_enum_attribute(kind_id, 1);
|
let attr = env.context.create_enum_attribute(kind_id, 1);
|
||||||
|
@ -303,6 +306,9 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// called from zig, must use C calling convention
|
||||||
|
function_value.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
||||||
debug_assert!(kind_id > 0);
|
debug_assert!(kind_id > 0);
|
||||||
let attr = env.context.create_enum_attribute(kind_id, 1);
|
let attr = env.context.create_enum_attribute(kind_id, 1);
|
||||||
|
@ -381,6 +387,9 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
&[arg_type.into(), arg_type.into()],
|
&[arg_type.into(), arg_type.into()],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// called from zig, must use C calling convention
|
||||||
|
function_value.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
||||||
debug_assert!(kind_id > 0);
|
debug_assert!(kind_id > 0);
|
||||||
let attr = env.context.create_enum_attribute(kind_id, 1);
|
let attr = env.context.create_enum_attribute(kind_id, 1);
|
||||||
|
@ -455,6 +464,9 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
&[arg_type.into(), arg_type.into(), arg_type.into()],
|
&[arg_type.into(), arg_type.into(), arg_type.into()],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// called from zig, must use C calling convention
|
||||||
|
function_value.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
// we expose this function to zig; must use c calling convention
|
// we expose this function to zig; must use c calling convention
|
||||||
function_value.set_call_conventions(C_CALL_CONV);
|
function_value.set_call_conventions(C_CALL_CONV);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ use crate::llvm::refcounting::{
|
||||||
};
|
};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use either::Either;
|
|
||||||
use inkwell::basic_block::BasicBlock;
|
use inkwell::basic_block::BasicBlock;
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
|
@ -38,8 +37,8 @@ use inkwell::passes::{PassManager, PassManagerBuilder};
|
||||||
use inkwell::types::{BasicType, BasicTypeEnum, FunctionType, IntType, StructType};
|
use inkwell::types::{BasicType, BasicTypeEnum, FunctionType, IntType, StructType};
|
||||||
use inkwell::values::BasicValueEnum::{self, *};
|
use inkwell::values::BasicValueEnum::{self, *};
|
||||||
use inkwell::values::{
|
use inkwell::values::{
|
||||||
BasicValue, CallSiteValue, FloatValue, FunctionValue, InstructionOpcode, InstructionValue,
|
BasicValue, CallSiteValue, CallableValue, FloatValue, FunctionValue, InstructionOpcode,
|
||||||
IntValue, PointerValue, StructValue,
|
InstructionValue, IntValue, PointerValue, StructValue,
|
||||||
};
|
};
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::{AddressSpace, IntPredicate};
|
use inkwell::{AddressSpace, IntPredicate};
|
||||||
|
@ -54,7 +53,7 @@ use roc_mono::ir::{
|
||||||
Wrapped,
|
Wrapped,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, InPlace, LambdaSet, Layout, LayoutIds, UnionLayout};
|
use roc_mono::layout::{Builtin, InPlace, LambdaSet, Layout, LayoutIds, UnionLayout};
|
||||||
use target_lexicon::CallingConvention;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
||||||
|
@ -1841,7 +1840,7 @@ fn invoke_roc_function<'a, 'ctx, 'env>(
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
layout: Layout<'a>,
|
layout: Layout<'a>,
|
||||||
function_value: Either<FunctionValue<'ctx>, PointerValue<'ctx>>,
|
function_value: FunctionValue<'ctx>,
|
||||||
arguments: &[Symbol],
|
arguments: &[Symbol],
|
||||||
closure_argument: Option<BasicValueEnum<'ctx>>,
|
closure_argument: Option<BasicValueEnum<'ctx>>,
|
||||||
pass: &'a roc_mono::ir::Stmt<'a>,
|
pass: &'a roc_mono::ir::Stmt<'a>,
|
||||||
|
@ -1869,14 +1868,7 @@ fn invoke_roc_function<'a, 'ctx, 'env>(
|
||||||
"tmp",
|
"tmp",
|
||||||
);
|
);
|
||||||
|
|
||||||
match function_value {
|
call.set_call_convention(function_value.get_call_conventions());
|
||||||
Either::Left(function) => {
|
|
||||||
call.set_call_convention(function.get_call_conventions());
|
|
||||||
}
|
|
||||||
Either::Right(_) => {
|
|
||||||
call.set_call_convention(FAST_CALL_CONV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
call.try_as_basic_value()
|
call.try_as_basic_value()
|
||||||
.left()
|
.left()
|
||||||
|
@ -1903,10 +1895,13 @@ fn invoke_roc_function<'a, 'ctx, 'env>(
|
||||||
context.struct_type(&[exception_ptr, selector_value], false)
|
context.struct_type(&[exception_ptr, selector_value], false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let exception_object = env.builder.build_cleanup_landing_pad(
|
let personality_function = get_gxx_personality_v0(env);
|
||||||
&landing_pad_type,
|
|
||||||
&BasicValueEnum::IntValue(context.i8_type().const_zero()),
|
let exception_object = env.builder.build_landing_pad(
|
||||||
context.i8_type().ptr_type(AddressSpace::Generic),
|
landing_pad_type,
|
||||||
|
personality_function,
|
||||||
|
&[],
|
||||||
|
true,
|
||||||
"invoke_landing_pad",
|
"invoke_landing_pad",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2059,7 +2054,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
parent,
|
parent,
|
||||||
*symbol,
|
*symbol,
|
||||||
*layout,
|
*layout,
|
||||||
function_value.into(),
|
function_value,
|
||||||
call.arguments,
|
call.arguments,
|
||||||
None,
|
None,
|
||||||
pass,
|
pass,
|
||||||
|
@ -2099,7 +2094,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
Resume(exception_id) => {
|
Resume(exception_id) => {
|
||||||
let exception_object = scope.get(&exception_id.into_inner()).unwrap().1;
|
let exception_object = scope.get(&exception_id.into_inner()).unwrap().1;
|
||||||
env.builder.build_resume(&exception_object);
|
env.builder.build_resume(exception_object);
|
||||||
|
|
||||||
env.context.i64_type().const_zero().into()
|
env.context.i64_type().const_zero().into()
|
||||||
}
|
}
|
||||||
|
@ -2854,18 +2849,17 @@ fn invoke_and_catch<'a, 'ctx, 'env, F, T>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
function: F,
|
function: F,
|
||||||
|
calling_convention: u32,
|
||||||
arguments: &[BasicValueEnum<'ctx>],
|
arguments: &[BasicValueEnum<'ctx>],
|
||||||
return_type: T,
|
return_type: T,
|
||||||
) -> BasicValueEnum<'ctx>
|
) -> BasicValueEnum<'ctx>
|
||||||
where
|
where
|
||||||
F: Into<either::Either<FunctionValue<'ctx>, PointerValue<'ctx>>>,
|
|
||||||
T: inkwell::types::BasicType<'ctx>,
|
T: inkwell::types::BasicType<'ctx>,
|
||||||
|
F: Into<CallableValue<'ctx>>,
|
||||||
{
|
{
|
||||||
let context = env.context;
|
let context = env.context;
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let call_result_type = context.struct_type(
|
let call_result_type = context.struct_type(
|
||||||
&[context.i64_type().into(), return_type.as_basic_type_enum()],
|
&[context.i64_type().into(), return_type.as_basic_type_enum()],
|
||||||
false,
|
false,
|
||||||
|
@ -2886,7 +2880,7 @@ where
|
||||||
catch_block,
|
catch_block,
|
||||||
"call_roc_function",
|
"call_roc_function",
|
||||||
);
|
);
|
||||||
call.set_call_convention(FAST_CALL_CONV);
|
call.set_call_convention(calling_convention);
|
||||||
call.try_as_basic_value().left().unwrap()
|
call.try_as_basic_value().left().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2894,6 +2888,51 @@ where
|
||||||
{
|
{
|
||||||
builder.position_at_end(catch_block);
|
builder.position_at_end(catch_block);
|
||||||
|
|
||||||
|
build_catch_all_landing_pad(env, result_alloca);
|
||||||
|
|
||||||
|
builder.build_unconditional_branch(cont_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
builder.position_at_end(then_block);
|
||||||
|
|
||||||
|
let return_value = {
|
||||||
|
let v1 = call_result_type.const_zero();
|
||||||
|
|
||||||
|
let v2 = builder
|
||||||
|
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
||||||
|
.unwrap();
|
||||||
|
let v3 = builder
|
||||||
|
.build_insert_value(v2, call_result, 1, "set_call_result")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
v3
|
||||||
|
};
|
||||||
|
|
||||||
|
let ptr = builder.build_bitcast(
|
||||||
|
result_alloca,
|
||||||
|
call_result_type.ptr_type(AddressSpace::Generic),
|
||||||
|
"name",
|
||||||
|
);
|
||||||
|
builder.build_store(ptr.into_pointer_value(), return_value);
|
||||||
|
|
||||||
|
builder.build_unconditional_branch(cont_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.position_at_end(cont_block);
|
||||||
|
|
||||||
|
builder.build_load(result_alloca, "result")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_catch_all_landing_pad<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
result_alloca: PointerValue<'ctx>,
|
||||||
|
) {
|
||||||
|
let context = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let landing_pad_type = {
|
let landing_pad_type = {
|
||||||
let exception_ptr = context.i8_type().ptr_type(AddressSpace::Generic).into();
|
let exception_ptr = context.i8_type().ptr_type(AddressSpace::Generic).into();
|
||||||
let selector_value = context.i32_type().into();
|
let selector_value = context.i32_type().into();
|
||||||
|
@ -2901,11 +2940,17 @@ where
|
||||||
context.struct_type(&[exception_ptr, selector_value], false)
|
context.struct_type(&[exception_ptr, selector_value], false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// null pointer functions as a catch-all catch clause
|
||||||
|
let null = u8_ptr.const_zero();
|
||||||
|
|
||||||
|
let personality_function = get_gxx_personality_v0(env);
|
||||||
|
|
||||||
let info = builder
|
let info = builder
|
||||||
.build_catch_all_landing_pad(
|
.build_landing_pad(
|
||||||
&landing_pad_type,
|
landing_pad_type,
|
||||||
&BasicValueEnum::IntValue(context.i8_type().const_zero()),
|
personality_function,
|
||||||
context.i8_type().ptr_type(AddressSpace::Generic),
|
&[null.into()],
|
||||||
|
false,
|
||||||
"main_landing_pad",
|
"main_landing_pad",
|
||||||
)
|
)
|
||||||
.into_struct_value();
|
.into_struct_value();
|
||||||
|
@ -2959,46 +3004,6 @@ where
|
||||||
builder.build_store(result_alloca_bitcast, return_value);
|
builder.build_store(result_alloca_bitcast, return_value);
|
||||||
|
|
||||||
cxa_end_catch(env);
|
cxa_end_catch(env);
|
||||||
|
|
||||||
builder.build_unconditional_branch(cont_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
builder.position_at_end(then_block);
|
|
||||||
|
|
||||||
let return_value = {
|
|
||||||
let v1 = call_result_type.const_zero();
|
|
||||||
|
|
||||||
let v2 = builder
|
|
||||||
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
|
||||||
.unwrap();
|
|
||||||
let v3 = builder
|
|
||||||
.build_insert_value(v2, call_result, 1, "set_call_result")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
v3
|
|
||||||
};
|
|
||||||
|
|
||||||
let ptr = builder.build_bitcast(
|
|
||||||
result_alloca,
|
|
||||||
call_result_type.ptr_type(AddressSpace::Generic),
|
|
||||||
"name",
|
|
||||||
);
|
|
||||||
builder.build_store(ptr.into_pointer_value(), return_value);
|
|
||||||
|
|
||||||
builder.build_unconditional_branch(cont_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.position_at_end(cont_block);
|
|
||||||
|
|
||||||
let result = builder.build_load(result_alloca, "result");
|
|
||||||
|
|
||||||
// MUST set the personality at the very end;
|
|
||||||
// doing it earlier can cause the personality to be ignored
|
|
||||||
let personality_func = get_gxx_personality_v0(env);
|
|
||||||
parent.set_personality_function(personality_func);
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_exception_catcher<'a, 'ctx, 'env>(
|
fn make_exception_catcher<'a, 'ctx, 'env>(
|
||||||
|
@ -3064,17 +3069,13 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
wrapper_function,
|
wrapper_function,
|
||||||
roc_function,
|
roc_function,
|
||||||
|
roc_function.get_call_conventions(),
|
||||||
&arguments,
|
&arguments,
|
||||||
roc_function_type.get_return_type().unwrap(),
|
roc_function_type.get_return_type().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.build_return(Some(&result));
|
builder.build_return(Some(&result));
|
||||||
|
|
||||||
// MUST set the personality at the very end;
|
|
||||||
// doing it earlier can cause the personality to be ignored
|
|
||||||
let personality_func = get_gxx_personality_v0(env);
|
|
||||||
wrapper_function.set_personality_function(personality_func);
|
|
||||||
|
|
||||||
wrapper_function
|
wrapper_function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3361,8 +3362,14 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||||
}
|
}
|
||||||
|
|
||||||
let call_result =
|
let call_result = invoke_and_catch(
|
||||||
invoke_and_catch(env, function_value, evaluator, &[closure_data], result_type);
|
env,
|
||||||
|
function_value,
|
||||||
|
evaluator,
|
||||||
|
evaluator.get_call_conventions(),
|
||||||
|
&[closure_data],
|
||||||
|
result_type,
|
||||||
|
);
|
||||||
|
|
||||||
builder.build_store(output, call_result);
|
builder.build_store(output, call_result);
|
||||||
|
|
||||||
|
@ -3476,7 +3483,14 @@ fn build_function_caller<'a, 'ctx, 'env>(
|
||||||
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||||
}
|
}
|
||||||
|
|
||||||
let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type);
|
let call_result = invoke_and_catch(
|
||||||
|
env,
|
||||||
|
function_value,
|
||||||
|
CallableValue::try_from(function_ptr).unwrap(),
|
||||||
|
C_CALL_CONV,
|
||||||
|
¶meters,
|
||||||
|
result_type,
|
||||||
|
);
|
||||||
|
|
||||||
builder.build_store(output, call_result);
|
builder.build_store(output, call_result);
|
||||||
|
|
||||||
|
@ -3733,8 +3747,8 @@ fn roc_call_with_args<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
/// Translates a target_lexicon::Triple to a LLVM calling convention u32
|
/// Translates a target_lexicon::Triple to a LLVM calling convention u32
|
||||||
/// as described in https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
/// as described in https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
||||||
pub fn get_call_conventions(cc: CallingConvention) -> u32 {
|
pub fn get_call_conventions(cc: target_lexicon::CallingConvention) -> u32 {
|
||||||
use CallingConvention::*;
|
use target_lexicon::CallingConvention::*;
|
||||||
|
|
||||||
// For now, we're returning 0 for the C calling convention on all of these.
|
// For now, we're returning 0 for the C calling convention on all of these.
|
||||||
// Not sure if we should be picking something more specific!
|
// Not sure if we should be picking something more specific!
|
||||||
|
@ -3746,9 +3760,9 @@ pub fn get_call_conventions(cc: CallingConvention) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Source: https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
/// Source: https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
||||||
pub static C_CALL_CONV: u32 = 0;
|
pub const C_CALL_CONV: u32 = 0;
|
||||||
pub static FAST_CALL_CONV: u32 = 8;
|
pub const FAST_CALL_CONV: u32 = 8;
|
||||||
pub static COLD_CALL_CONV: u32 = 9;
|
pub const COLD_CALL_CONV: u32 = 9;
|
||||||
|
|
||||||
pub struct RocFunctionCall<'ctx> {
|
pub struct RocFunctionCall<'ctx> {
|
||||||
pub caller: PointerValue<'ctx>,
|
pub caller: PointerValue<'ctx>,
|
||||||
|
@ -5102,10 +5116,13 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
|
||||||
.struct_type(&[exception_ptr, selector_value], false)
|
.struct_type(&[exception_ptr, selector_value], false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let exception_object = env.builder.build_cleanup_landing_pad(
|
let personality_function = get_gxx_personality_v0(env);
|
||||||
&landing_pad_type,
|
|
||||||
&BasicValueEnum::IntValue(env.context.i8_type().const_zero()),
|
let exception_object = env.builder.build_landing_pad(
|
||||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
landing_pad_type,
|
||||||
|
personality_function,
|
||||||
|
&[],
|
||||||
|
true,
|
||||||
"invoke_landing_pad",
|
"invoke_landing_pad",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
16
nightly_benches/Cargo.toml
Normal file
16
nightly_benches/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "nightly_benches"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
criterion = { git = "https://github.com/Anton-4/criterion.rs"}
|
||||||
|
cli_utils = { path = "../cli/cli_utils" }
|
||||||
|
criterion-perf-events ={ git = "https://github.com/Anton-4/criterion-perf-events" }
|
||||||
|
perfcnt = "0.7.1"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "events_bench"
|
||||||
|
harness = false
|
14
nightly_benches/README.me
Normal file
14
nightly_benches/README.me
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Running benchmarks
|
||||||
|
|
||||||
|
Install cargo criterion:
|
||||||
|
```
|
||||||
|
cargo install --git https://github.com/Anton-4/cargo-criterion --branch main
|
||||||
|
```
|
||||||
|
Necessary to get cache misses...:
|
||||||
|
```
|
||||||
|
sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'
|
||||||
|
```
|
||||||
|
run:
|
||||||
|
```
|
||||||
|
cargo criterion
|
||||||
|
```
|
|
@ -1,6 +1,6 @@
|
||||||
// Keep this benchmark. It's commented because it requires nightly rust.
|
// Keep this benchmark. It's commented because it requires nightly rust.
|
||||||
/*use cli_utils::bench_utils::{
|
use cli_utils::bench_utils::{
|
||||||
bench_cfold, bench_deriv, bench_nqueens, bench_rbtree_ck, bench_rbtree_delete,
|
bench_cfold, bench_deriv, bench_nqueens, bench_rbtree_ck, bench_rbtree_delete, bench_quicksort
|
||||||
};
|
};
|
||||||
use criterion_perf_events::Perf;
|
use criterion_perf_events::Perf;
|
||||||
use perfcnt::linux::HardwareEventType as Hardware;
|
use perfcnt::linux::HardwareEventType as Hardware;
|
||||||
|
@ -19,7 +19,7 @@ fn bench_group(c: &mut Criterion<Perf>, hw_event_str: &str) {
|
||||||
bench_deriv,
|
bench_deriv,
|
||||||
bench_rbtree_ck,
|
bench_rbtree_ck,
|
||||||
bench_rbtree_delete,
|
bench_rbtree_delete,
|
||||||
// TODO quicksort
|
bench_quicksort,
|
||||||
];
|
];
|
||||||
|
|
||||||
for bench_func in bench_funcs.iter() {
|
for bench_func in bench_funcs.iter() {
|
||||||
|
@ -91,4 +91,4 @@ criterion_main!(
|
||||||
benches_cache_misses,
|
benches_cache_misses,
|
||||||
benches_branch_instructions,
|
benches_branch_instructions,
|
||||||
benches_branch_misses
|
benches_branch_misses
|
||||||
);*/
|
);
|
1
nightly_benches/rust-toolchain
Normal file
1
nightly_benches/rust-toolchain
Normal file
|
@ -0,0 +1 @@
|
||||||
|
nightly
|
8
nightly_benches/src/main.rs
Normal file
8
nightly_benches/src/main.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {
|
||||||
|
println!("""
|
||||||
|
To run benchmarks:
|
||||||
|
- Install cargo criterion: cargo install --git https://github.com/Anton-4/cargo-criterion --branch main
|
||||||
|
- Necessary to get cache misses...: sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'
|
||||||
|
- run: cargo criterion
|
||||||
|
""");
|
||||||
|
}
|
2
vendor/inkwell/Cargo.toml
vendored
2
vendor/inkwell/Cargo.toml
vendored
|
@ -23,7 +23,7 @@ edition = "2018"
|
||||||
# commit of TheDan64/inkwell, push a new tag which points to the latest commit,
|
# commit of TheDan64/inkwell, push a new tag which points to the latest commit,
|
||||||
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
||||||
# This way, GitHub Actions works and nobody's builds get broken.
|
# This way, GitHub Actions works and nobody's builds get broken.
|
||||||
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm12-0.release4", features = [ "llvm12-0" ] }
|
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm12-0.release5", features = [ "llvm12-0" ] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target-arm = []
|
target-arm = []
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue