mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 22:01:20 +00:00
Merge branch 'main' into markdown
Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com>
This commit is contained in:
commit
322ae187bc
34 changed files with 558 additions and 288 deletions
42
.github/workflows/nightly_macos_x86_64.yml
vendored
42
.github/workflows/nightly_macos_x86_64.yml
vendored
|
|
@ -1,6 +1,6 @@
|
|||
on:
|
||||
schedule:
|
||||
- cron: '0 9 * * 1' # 9=9am utc+0, 1=monday
|
||||
- cron: '0 9 * * *' # 9=9am utc+0
|
||||
|
||||
name: Nightly Release macOS x86_64
|
||||
|
||||
|
|
@ -9,8 +9,8 @@ env:
|
|||
LLVM_SYS_130_PREFIX: /usr/local/opt/llvm
|
||||
|
||||
jobs:
|
||||
test-and-build:
|
||||
name: Rust tests, build and package nightly release
|
||||
test-build-upload:
|
||||
name: build, test, package and upload nightly release
|
||||
runs-on: [macos-12]
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
|
|
@ -24,30 +24,42 @@ jobs:
|
|||
run: zig version
|
||||
- name: Install LLVM
|
||||
run: brew install llvm@13
|
||||
|
||||
# build has to be done before tests #2572
|
||||
- name: build release
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --release --locked
|
||||
|
||||
- name: execute rust tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --locked # no --release yet until #3166 is fixed
|
||||
args: --release --locked -- --skip opaque_wrap_function --skip bool_list_literal
|
||||
|
||||
- name: get commit SHA
|
||||
run: echo "SHA=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_ENV
|
||||
|
||||
- name: get date
|
||||
run: echo "DATE=$(date "+%Y-%m-%d")" >> $GITHUB_ENV
|
||||
|
||||
- name: build file name
|
||||
env:
|
||||
DATE: ${{ env.DATE }}
|
||||
SHA: ${{ env.SHA }}
|
||||
run: echo "RELEASE_TAR_FILENAME=roc_nightly-macos_x86_64-$DATE-$SHA.tar.gz" >> $GITHUB_ENV
|
||||
|
||||
- name: write version to file
|
||||
run: ./ci/write_version.sh
|
||||
|
||||
- name: package release
|
||||
run: ./ci/package_release.sh roc_darwin_x86_64.tar.gz
|
||||
- name: Create pre-release with test_archive.tar.gz
|
||||
uses: Anton-4/deploy-nightly@1609d8dfe211b078674801113ab7a2ec2938b2a9
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
|
||||
run: ./ci/package_release.sh ${{ env.RELEASE_TAR_FILENAME }}
|
||||
|
||||
- name: Upload artifact. Actually uploading to github releases has to be done manually.
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/roc-lang/roc/releases/51880579/assets{?name,label}
|
||||
release_id: 51880579
|
||||
asset_path: ./roc_darwin_x86_64.tar.gz
|
||||
asset_name: roc_nightly-macos_x86_64-$$.tar.gz # $$ inserts 6 char commit hash and date (YYYY-MM-DD)
|
||||
asset_content_type: application/gzip
|
||||
max_releases: 3
|
||||
name: ${{ env.RELEASE_TAR_FILENAME }}
|
||||
path: ${{ env.RELEASE_TAR_FILENAME }}
|
||||
retention-days: 4
|
||||
|
||||
|
|
|
|||
9
.github/workflows/spellcheck.yml
vendored
9
.github/workflows/spellcheck.yml
vendored
|
|
@ -12,7 +12,7 @@ env:
|
|||
jobs:
|
||||
spell-check:
|
||||
name: spell check
|
||||
runs-on: [self-hosted, i7-6700K]
|
||||
runs-on: [self-hosted]
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
|
@ -21,8 +21,5 @@ jobs:
|
|||
with:
|
||||
clean: "true"
|
||||
|
||||
- name: Earthly version
|
||||
run: earthly --version
|
||||
|
||||
- name: install spell checker, do spell check
|
||||
run: ./ci/safe-earthly.sh +check-typos
|
||||
- name: do spell check with typos-cli 1.0.11 # to reproduce locally: cargo install typos-cli --version 1.0.11
|
||||
run: typos
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ on:
|
|||
name: Test latest nightly release for macOS Apple Silicon
|
||||
|
||||
jobs:
|
||||
test-and-build:
|
||||
test-nightly:
|
||||
name: test nightly macos aarch64
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 90
|
||||
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
run: curl https://api.github.com/repos/roc-lang/roc/releases > roc_releases.json
|
||||
|
||||
- name: get the url of today`s release for macos apple silicon
|
||||
run: echo "RELEASE_URL=$(./ci/get_latest_release_url.sh)" >> $GITHUB_ENV
|
||||
run: echo "RELEASE_URL=$(./ci/get_latest_release_url.sh silicon)" >> $GITHUB_ENV
|
||||
|
||||
- name: get the archive from the url
|
||||
run: curl -OL ${{ env.RELEASE_URL }}
|
||||
34
.github/workflows/test_nightly_macos_x86_64.yml
vendored
Normal file
34
.github/workflows/test_nightly_macos_x86_64.yml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
on:
|
||||
schedule:
|
||||
- cron: '0 13 * * *'
|
||||
|
||||
name: Test latest nightly release for macOS x86_64
|
||||
|
||||
jobs:
|
||||
test-nightly:
|
||||
name: test nightly macos x86_64
|
||||
runs-on: [ macos-12 ]
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: fetch releases data and save to file
|
||||
run: curl https://api.github.com/repos/roc-lang/roc/releases > roc_releases.json
|
||||
|
||||
- name: get the url of today`s release for macos apple silicon
|
||||
run: echo "RELEASE_URL=$(./ci/get_latest_release_url.sh macos_x86_64)" >> $GITHUB_ENV
|
||||
|
||||
- name: get the archive from the url
|
||||
run: curl -OL ${{ env.RELEASE_URL }}
|
||||
|
||||
- name: remove everything in this dir except the tar # we want to test like a user who would have downloaded the release, so we clean up all files from the repo checkout
|
||||
run: ls | grep -v "roc_nightly.*tar\.gz" | xargs rm -rf
|
||||
|
||||
- name: decompress the tar
|
||||
run: ls | grep "roc_nightly.*tar\.gz" | xargs tar -xzvf
|
||||
|
||||
- name: test roc hello world
|
||||
run: ./roc examples/hello-world/main.roc
|
||||
|
||||
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -1638,9 +1638,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glyph_brush"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a69c65dd1f1fbb6209aa00f78636e436ad0a55b7d8e5de886d00720dcad9c6e2"
|
||||
checksum = "ac02497410cdb5062cc056a33f2e1e19ff69fbf26a4be9a02bf29d6e17ea105b"
|
||||
dependencies = [
|
||||
"glyph_brush_draw_cache",
|
||||
"glyph_brush_layout",
|
||||
|
|
|
|||
78
Earthfile
78
Earthfile
|
|
@ -52,84 +52,6 @@ copy-dirs:
|
|||
FROM +install-zig-llvm-valgrind
|
||||
COPY --dir crates examples Cargo.toml Cargo.lock version.txt www ./
|
||||
|
||||
test-zig:
|
||||
FROM +install-zig-llvm-valgrind
|
||||
COPY --dir crates/compiler/builtins/bitcode ./
|
||||
RUN cd bitcode && ./run-tests.sh && ./run-wasm-tests.sh
|
||||
|
||||
build-rust-test:
|
||||
FROM +copy-dirs
|
||||
RUN echo "deb http://deb.debian.org/debian testing main contrib non-free" >> /etc/apt/sources.list # to get gcc 10.3
|
||||
RUN apt -y update
|
||||
RUN apt -y install gcc-10 g++-10 && rm /usr/bin/gcc && ln -s /usr/bin/gcc-10 /usr/bin/gcc # gcc-9 maybe causes segfault
|
||||
RUN gcc --version
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo test --locked --release --features with_sound serde --workspace --no-run && sccache --show-stats
|
||||
|
||||
check-typos:
|
||||
RUN cargo install typos-cli --version 1.0.11 # version set to prevent confusion if the version is updated automatically
|
||||
COPY --dir .github ci crates examples nightly_benches www *.md LEGAL_DETAILS flake.nix version.txt ./
|
||||
RUN typos
|
||||
|
||||
test-rust:
|
||||
FROM +build-rust-test
|
||||
ENV ROC_WORKSPACE_DIR=/earthbuild
|
||||
ENV RUST_BACKTRACE=1
|
||||
# for race condition problem with cli test
|
||||
ENV ROC_NUM_WORKERS=1
|
||||
# run one of the benchmarks to make sure the host is compiled
|
||||
# not pre-compiling the host can cause race conditions
|
||||
RUN gcc --version
|
||||
RUN echo "4" | cargo run --release examples/benchmarks/NQueens.roc
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo test --locked --release --features with_sound serde --workspace && sccache --show-stats
|
||||
# test the dev and wasm backend: they require an explicit feature flag.
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo test --locked --release --package test_gen --no-default-features --features gen-dev && sccache --show-stats
|
||||
# gen-wasm has some multithreading problems to do with the wasmer runtime. Run it single-threaded as a separate job
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo test --locked --release --package test_gen --no-default-features --features gen-wasm -- --test-threads=1 && sccache --show-stats
|
||||
# run `roc test` on Str builtins
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
cargo run --release -- test crates/compiler/builtins/roc/Str.roc && sccache --show-stats
|
||||
# repl_test: build the compiler for wasm target, then run the tests on native target
|
||||
RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
crates/repl_test/test_wasm.sh && sccache --show-stats
|
||||
# run i386 (32-bit linux) cli tests
|
||||
# NOTE: disabled until zig 0.9
|
||||
# RUN echo "4" | cargo run --locked --release --features="target-x86" -- --target=x86_32 examples/benchmarks/NQueens.roc
|
||||
# RUN --mount=type=cache,target=$SCCACHE_DIR \
|
||||
# cargo test --locked --release --features with_sound serde --test cli_run i386 --features="i386-cli-run" && sccache --show-stats
|
||||
# make sure website deployment works (that is, make sure build.sh returns status code 0)
|
||||
ENV REPL_DEBUG=1
|
||||
RUN bash www/build.sh
|
||||
|
||||
|
||||
verify-no-git-changes:
|
||||
FROM +test-rust
|
||||
# If running tests caused anything to be changed or added (without being
|
||||
# included in a .gitignore somewhere), fail the build!
|
||||
#
|
||||
# How it works: the `git ls-files` command lists all the modified or
|
||||
# uncommitted files in the working tree, the `| grep -E .` command returns a
|
||||
# zero exit code if it listed any files and nonzero otherwise (which is the
|
||||
# opposite of what we want), and the `!` at the start inverts the exit code.
|
||||
RUN ! git ls-files --deleted --modified --others --exclude-standard | grep -E .
|
||||
|
||||
test-all:
|
||||
BUILD +test-zig
|
||||
BUILD +test-rust
|
||||
BUILD +verify-no-git-changes
|
||||
|
||||
build-nightly-release:
|
||||
FROM +test-rust
|
||||
COPY --dir .git LICENSE LEGAL_DETAILS ci ./
|
||||
# version.txt is used by the CLI: roc --version
|
||||
RUN ./ci/write_version.sh
|
||||
RUN RUSTFLAGS="-C target-cpu=x86-64" cargo build --features with_sound --release
|
||||
RUN ./ci/package_release.sh roc_linux_x86_64.tar.gz
|
||||
SAVE ARTIFACT ./roc_linux_x86_64.tar.gz AS LOCAL roc_linux_x86_64.tar.gz
|
||||
|
||||
# compile everything needed for benchmarks and output a self-contained dir from which benchmarks can be run.
|
||||
prep-bench-folder:
|
||||
FROM +copy-dirs
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# assumes roc_releases.json is present
|
||||
|
||||
LATEST_RELEASE_URL=`cat roc_releases.json | jq --arg today $(date +'%Y-%m-%d') '.[0] | .assets | map(.browser_download_url) | map(select(. | contains("silicon-\($today)"))) | .[0]'`
|
||||
LATEST_RELEASE_URL=`cat roc_releases.json | jq --arg arch $1 --arg today $(date +'%Y-%m-%d') '.[0] | .assets | map(.browser_download_url) | map(select(. | contains("\($arch)-\($today)"))) | .[0]'`
|
||||
|
||||
if [[ "$LATEST_RELEASE_URL" == "null" ]]
|
||||
then
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ mod cli_run {
|
|||
// We exclude the C platforming switching example
|
||||
// because the main platform switching example runs the c platform.
|
||||
// If we don't a race condition leads to test flakiness.
|
||||
// platformSwitchingC:"platform-switching/c-platform" => Example {
|
||||
// platformSwitchingC:"platform-switching" => Example {
|
||||
// filename: "rocLovesC.roc",
|
||||
// executable_filename: "rocLovesC",
|
||||
// stdin: &[],
|
||||
|
|
@ -394,7 +394,7 @@ mod cli_run {
|
|||
// expected_ending:"Roc <3 C!\n",
|
||||
// use_valgrind: true,
|
||||
// },
|
||||
platformSwitchingRust:"platform-switching/rust-platform" => Example {
|
||||
platformSwitchingRust:"platform-switching" => Example {
|
||||
filename: "rocLovesRust.roc",
|
||||
executable_filename: "rocLovesRust",
|
||||
stdin: &[],
|
||||
|
|
@ -402,7 +402,7 @@ mod cli_run {
|
|||
expected_ending:"Roc <3 Rust!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
platformSwitchingSwift:"platform-switching/swift-platform" => Example {
|
||||
platformSwitchingSwift:"platform-switching" => Example {
|
||||
filename: "rocLovesSwift.roc",
|
||||
executable_filename: "rocLovesSwift",
|
||||
stdin: &[],
|
||||
|
|
@ -410,7 +410,7 @@ mod cli_run {
|
|||
expected_ending:"Roc <3 Swift!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
platformSwitchingWebAssembly:"platform-switching/web-assembly-platform" => Example {
|
||||
platformSwitchingWebAssembly:"platform-switching" => Example {
|
||||
filename: "rocLovesWebAssembly.roc",
|
||||
executable_filename: "rocLovesWebAssembly",
|
||||
stdin: &[],
|
||||
|
|
@ -418,7 +418,7 @@ mod cli_run {
|
|||
expected_ending:"Roc <3 Web Assembly!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
platformSwitchingZig:"platform-switching/zig-platform" => Example {
|
||||
platformSwitchingZig:"platform-switching" => Example {
|
||||
filename: "rocLovesZig.roc",
|
||||
executable_filename: "rocLovesZig",
|
||||
stdin: &[],
|
||||
|
|
@ -821,25 +821,6 @@ mod cli_run {
|
|||
if entry.file_type().unwrap().is_dir() {
|
||||
let example_dir_name = entry.file_name().into_string().unwrap();
|
||||
|
||||
// TODO: Improve this with a more-dynamic approach. (Read all subdirectories?)
|
||||
// Some platform-switching examples live in nested directories
|
||||
if example_dir_name == "platform-switching" {
|
||||
for sub_dir in [
|
||||
// We exclude the C platforming switching example
|
||||
// because the main platform switching example runs the c platform.
|
||||
// If we don't a race condition leads to test flakiness.
|
||||
// "c-platform",
|
||||
"rust-platform",
|
||||
"swift-platform",
|
||||
"web-assembly-platform",
|
||||
"zig-platform",
|
||||
] {
|
||||
all_examples.remove(format!("{}/{}", example_dir_name, sub_dir).as_str()).unwrap_or_else(|| {
|
||||
panic!("The example directory {}/{}/{} does not have any corresponding tests in cli_run. Please add one, so if it ever stops working, we'll know about it right away!", examples_dir, example_dir_name, sub_dir);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We test benchmarks separately
|
||||
if example_dir_name != "benchmarks" {
|
||||
all_examples.remove(example_dir_name.as_str()).unwrap_or_else(|| {
|
||||
|
|
|
|||
|
|
@ -148,9 +148,12 @@ pub const RocList = extern struct {
|
|||
) RocList {
|
||||
if (self.bytes) |source_ptr| {
|
||||
if (self.isUnique()) {
|
||||
const new_source = utils.unsafeReallocate(source_ptr, alignment, self.len(), new_length, element_width);
|
||||
|
||||
return RocList{ .bytes = new_source, .length = new_length, .capacity = new_length };
|
||||
if (self.capacity >= new_length) {
|
||||
return RocList{ .bytes = self.bytes, .length = new_length, .capacity = self.capacity };
|
||||
} else {
|
||||
const new_source = utils.unsafeReallocate(source_ptr, alignment, self.len(), new_length, element_width);
|
||||
return RocList{ .bytes = new_source, .length = new_length, .capacity = new_length };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -727,17 +730,20 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
|||
return list_b;
|
||||
} else if (list_b.isEmpty()) {
|
||||
return list_a;
|
||||
} else if (!list_a.isEmpty() and list_a.isUnique()) {
|
||||
} else if (list_a.isUnique()) {
|
||||
const total_length: usize = list_a.len() + list_b.len();
|
||||
|
||||
if (list_a.bytes) |source| {
|
||||
const new_source = utils.unsafeReallocate(
|
||||
source,
|
||||
alignment,
|
||||
list_a.len(),
|
||||
total_length,
|
||||
element_width,
|
||||
);
|
||||
const new_source = if (list_a.capacity >= total_length)
|
||||
source
|
||||
else
|
||||
utils.unsafeReallocate(
|
||||
source,
|
||||
alignment,
|
||||
list_a.len(),
|
||||
total_length,
|
||||
element_width,
|
||||
);
|
||||
|
||||
if (list_b.bytes) |source_b| {
|
||||
@memcpy(new_source + list_a.len() * element_width, source_b, list_b.len() * element_width);
|
||||
|
|
|
|||
|
|
@ -215,11 +215,14 @@ pub const RocStr = extern struct {
|
|||
return result;
|
||||
}
|
||||
|
||||
// NOTE: returns false for empty string!
|
||||
pub fn isSmallStr(self: RocStr) bool {
|
||||
return @bitCast(isize, self.str_capacity) < 0;
|
||||
}
|
||||
|
||||
test "isSmallStr: returns true for empty string" {
|
||||
try expect(isSmallStr(RocStr.empty()));
|
||||
}
|
||||
|
||||
fn asArray(self: RocStr) [@sizeOf(RocStr)]u8 {
|
||||
const as_ptr = @ptrCast([*]const u8, &self);
|
||||
const slice = as_ptr[0..@sizeOf(RocStr)];
|
||||
|
|
@ -1652,17 +1655,17 @@ pub fn strToUtf8C(arg: RocStr) callconv(.C) RocList {
|
|||
}
|
||||
|
||||
inline fn strToBytes(arg: RocStr) RocList {
|
||||
if (arg.isEmpty()) {
|
||||
const length = arg.len();
|
||||
if (length == 0) {
|
||||
return RocList.empty();
|
||||
} else if (arg.isSmallStr()) {
|
||||
const length = arg.len();
|
||||
const ptr = utils.allocateWithRefcount(length, RocStr.alignment);
|
||||
|
||||
@memcpy(ptr, arg.asU8ptr(), length);
|
||||
|
||||
return RocList{ .length = length, .bytes = ptr, .capacity = length };
|
||||
} else {
|
||||
return RocList{ .length = arg.len(), .bytes = arg.str_bytes, .capacity = arg.str_capacity };
|
||||
return RocList{ .length = length, .bytes = arg.str_bytes, .capacity = arg.str_capacity };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ pub fn unsafeReallocate(
|
|||
const old_width = align_width + old_length * element_width;
|
||||
const new_width = align_width + new_length * element_width;
|
||||
|
||||
if (old_width == new_width) {
|
||||
if (old_width >= new_width) {
|
||||
return source_ptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -834,6 +834,33 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
fn ret(buf: &mut Vec<'_, u8>) {
|
||||
ret_reg64(buf, AArch64GeneralReg::LR)
|
||||
}
|
||||
|
||||
fn and_reg64_reg64_reg64(
|
||||
_buf: &mut Vec<'_, u8>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
) {
|
||||
todo!("bitwise and for AArch64")
|
||||
}
|
||||
|
||||
fn or_reg64_reg64_reg64(
|
||||
_buf: &mut Vec<'_, u8>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
) {
|
||||
todo!("bitwise or for AArch64")
|
||||
}
|
||||
|
||||
fn xor_reg64_reg64_reg64(
|
||||
_buf: &mut Vec<'_, u8>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
) {
|
||||
todo!("bitwise xor for AArch64")
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64Assembler {}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,27 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
src2: GeneralReg,
|
||||
);
|
||||
|
||||
fn and_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
|
||||
fn or_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
|
||||
fn xor_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
|
||||
fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String);
|
||||
|
||||
/// Jumps by an offset of offset bytes unconditionally.
|
||||
|
|
@ -1600,6 +1621,66 @@ impl<
|
|||
offset,
|
||||
});
|
||||
}
|
||||
|
||||
fn build_int_bitwise_and(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
) {
|
||||
let buf = &mut self.buf;
|
||||
|
||||
match int_width {
|
||||
IntWidth::U128 | IntWidth::I128 => todo!(),
|
||||
_ => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_general_reg(buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_general_reg(buf, src2);
|
||||
ASM::and_reg64_reg64_reg64(buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_int_bitwise_or(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
) {
|
||||
let buf = &mut self.buf;
|
||||
|
||||
match int_width {
|
||||
IntWidth::U128 | IntWidth::I128 => todo!(),
|
||||
_ => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_general_reg(buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_general_reg(buf, src2);
|
||||
ASM::or_reg64_reg64_reg64(buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_int_bitwise_xor(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
) {
|
||||
let buf = &mut self.buf;
|
||||
|
||||
match int_width {
|
||||
IntWidth::U128 | IntWidth::I128 => todo!(),
|
||||
_ => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(buf, dst);
|
||||
let src1_reg = self.storage_manager.load_to_general_reg(buf, src1);
|
||||
let src2_reg = self.storage_manager.load_to_general_reg(buf, src2);
|
||||
ASM::xor_reg64_reg64_reg64(buf, dst_reg, src1_reg, src2_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This impl block is for ir related instructions that need backend specific information.
|
||||
|
|
|
|||
|
|
@ -916,6 +916,22 @@ fn x86_64_generic_cleanup_stack<'a>(
|
|||
X86_64Assembler::pop_reg64(buf, X86_64GeneralReg::RBP);
|
||||
}
|
||||
|
||||
type Reg64 = X86_64GeneralReg;
|
||||
|
||||
fn binop_move_src_to_dst_reg64<F>(buf: &mut Vec<'_, u8>, f: F, dst: Reg64, src1: Reg64, src2: Reg64)
|
||||
where
|
||||
F: FnOnce(&mut Vec<'_, u8>, X86_64GeneralReg, X86_64GeneralReg),
|
||||
{
|
||||
if dst == src1 {
|
||||
f(buf, dst, src2);
|
||||
} else if dst == src2 {
|
||||
f(buf, dst, src1);
|
||||
} else {
|
||||
mov_reg64_reg64(buf, dst, src1);
|
||||
f(buf, dst, src2);
|
||||
}
|
||||
}
|
||||
|
||||
impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||
// These functions should map to the raw assembly functions below.
|
||||
// In some cases, that means you can just directly call one of the direct assembly functions.
|
||||
|
|
@ -954,22 +970,12 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
mov_reg64_reg64(buf, dst, src1);
|
||||
add_reg64_imm32(buf, dst, imm32);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: X86_64GeneralReg,
|
||||
src1: X86_64GeneralReg,
|
||||
src2: X86_64GeneralReg,
|
||||
) {
|
||||
if dst == src1 {
|
||||
add_reg64_reg64(buf, dst, src2);
|
||||
} else if dst == src2 {
|
||||
add_reg64_reg64(buf, dst, src1);
|
||||
} else {
|
||||
mov_reg64_reg64(buf, dst, src1);
|
||||
add_reg64_reg64(buf, dst, src2);
|
||||
}
|
||||
fn add_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: Reg64, src1: Reg64, src2: Reg64) {
|
||||
binop_move_src_to_dst_reg64(buf, add_reg64_reg64, dst, src1, src2)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_freg32_freg32_freg32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
|
|
@ -1253,31 +1259,20 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
#[inline(always)]
|
||||
fn movsx_reg64_base32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
if size == 8 {
|
||||
Self::mov_reg64_base32(buf, dst, offset);
|
||||
} else if size == 4 {
|
||||
todo!("sign extending 4 byte values");
|
||||
} else if size == 2 {
|
||||
todo!("sign extending 2 byte values");
|
||||
} else if size == 1 {
|
||||
todo!("sign extending 1 byte values");
|
||||
} else {
|
||||
internal_error!("Invalid size for sign extension: {}", size);
|
||||
match size {
|
||||
8 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
4 | 2 | 1 => todo!("sign extending {size} byte values"),
|
||||
_ => internal_error!("Invalid size for sign extension: {size}"),
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn movzx_reg64_base32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
if size == 8 {
|
||||
Self::mov_reg64_base32(buf, dst, offset);
|
||||
} else if size == 4 {
|
||||
todo!("zero extending 4 byte values");
|
||||
} else if size == 2 {
|
||||
todo!("zero extending 2 byte values");
|
||||
} else if size == 1 {
|
||||
movzx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset);
|
||||
} else {
|
||||
internal_error!("Invalid size for zero extension: {}", size);
|
||||
match size {
|
||||
8 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
4 | 2 => todo!("zero extending {size} byte values"),
|
||||
1 => movzx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
_ => internal_error!("Invalid size for zero extension: {size}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1408,6 +1403,18 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
fn set_if_overflow(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg) {
|
||||
seto_reg64(buf, dst);
|
||||
}
|
||||
|
||||
fn and_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: Reg64, src1: Reg64, src2: Reg64) {
|
||||
binop_move_src_to_dst_reg64(buf, and_reg64_reg64, dst, src1, src2)
|
||||
}
|
||||
|
||||
fn or_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: Reg64, src1: Reg64, src2: Reg64) {
|
||||
binop_move_src_to_dst_reg64(buf, or_reg64_reg64, dst, src1, src2)
|
||||
}
|
||||
|
||||
fn xor_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: Reg64, src1: Reg64, src2: Reg64) {
|
||||
binop_move_src_to_dst_reg64(buf, xor_reg64_reg64, dst, src1, src2)
|
||||
}
|
||||
}
|
||||
|
||||
impl X86_64Assembler {
|
||||
|
|
@ -1511,6 +1518,27 @@ fn add_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64Gene
|
|||
binop_reg64_reg64(0x01, buf, dst, src);
|
||||
}
|
||||
|
||||
/// `AND r/m64,r64` -> Bitwise logical and r64 to r/m64.
|
||||
#[inline(always)]
|
||||
fn and_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) {
|
||||
// NOTE: src and dst are flipped by design
|
||||
binop_reg64_reg64(0x23, buf, src, dst);
|
||||
}
|
||||
|
||||
/// `OR r/m64,r64` -> Bitwise logical or r64 to r/m64.
|
||||
#[inline(always)]
|
||||
fn or_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) {
|
||||
// NOTE: src and dst are flipped by design
|
||||
binop_reg64_reg64(0x0B, buf, src, dst);
|
||||
}
|
||||
|
||||
/// `XOR r/m64,r64` -> Bitwise logical exclusive or r64 to r/m64.
|
||||
#[inline(always)]
|
||||
fn xor_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) {
|
||||
// NOTE: src and dst are flipped by design
|
||||
binop_reg64_reg64(0x33, buf, src, dst);
|
||||
}
|
||||
|
||||
/// `ADDSD xmm1,xmm2/m64` -> Add the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
|
||||
#[inline(always)]
|
||||
fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
|
||||
|
|
@ -2189,13 +2217,6 @@ fn push_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
|
|||
}
|
||||
}
|
||||
|
||||
/// `XOR r/m64,r64` -> Xor r64 to r/m64.
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
fn xor_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) {
|
||||
binop_reg64_reg64(0x31, buf, dst, src);
|
||||
}
|
||||
|
||||
// When writing tests, it is a good idea to test both a number and unnumbered register.
|
||||
// This is because R8-R15 often have special instruction prefixes.
|
||||
#[cfg(test)]
|
||||
|
|
@ -2341,11 +2362,31 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_and_reg64_reg64() {
|
||||
disassembler_test!(
|
||||
and_reg64_reg64,
|
||||
|reg1, reg2| format!("and {reg1}, {reg2}"),
|
||||
ALL_GENERAL_REGS,
|
||||
ALL_GENERAL_REGS
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_or_reg64_reg64() {
|
||||
disassembler_test!(
|
||||
or_reg64_reg64,
|
||||
|reg1, reg2| format!("or {reg1}, {reg2}"),
|
||||
ALL_GENERAL_REGS,
|
||||
ALL_GENERAL_REGS
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xor_reg64_reg64() {
|
||||
disassembler_test!(
|
||||
xor_reg64_reg64,
|
||||
|reg1, reg2| format!("xor {}, {}", reg1, reg2),
|
||||
|reg1, reg2| format!("xor {reg1}, {reg2}"),
|
||||
ALL_GENERAL_REGS,
|
||||
ALL_GENERAL_REGS
|
||||
);
|
||||
|
|
|
|||
|
|
@ -499,6 +499,27 @@ trait Backend<'a> {
|
|||
);
|
||||
self.build_num_sub(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
LowLevel::NumBitwiseAnd => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = ret_layout {
|
||||
self.build_int_bitwise_and(sym, &args[0], &args[1], *int_width)
|
||||
} else {
|
||||
internal_error!("bitwise and on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::NumBitwiseOr => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = ret_layout {
|
||||
self.build_int_bitwise_or(sym, &args[0], &args[1], *int_width)
|
||||
} else {
|
||||
internal_error!("bitwise or on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::NumBitwiseXor => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = ret_layout {
|
||||
self.build_int_bitwise_xor(sym, &args[0], &args[1], *int_width)
|
||||
} else {
|
||||
internal_error!("bitwise xor on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::Eq => {
|
||||
debug_assert_eq!(2, args.len(), "Eq: expected to have exactly two argument");
|
||||
debug_assert_eq!(
|
||||
|
|
@ -750,6 +771,33 @@ trait Backend<'a> {
|
|||
/// build_num_sub stores the `src1 - src2` difference into dst.
|
||||
fn build_num_sub(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>);
|
||||
|
||||
/// stores the `src1 & src2` into dst.
|
||||
fn build_int_bitwise_and(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
);
|
||||
|
||||
/// stores the `src1 | src2` into dst.
|
||||
fn build_int_bitwise_or(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
);
|
||||
|
||||
/// stores the `src1 ^ src2` into dst.
|
||||
fn build_int_bitwise_xor(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
int_width: IntWidth,
|
||||
);
|
||||
|
||||
/// build_eq stores the result of `src1 == src2` into dst.
|
||||
fn build_eq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &Layout<'a>);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use crate::llvm::build_list::{
|
|||
list_prepend, list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
|
||||
list_symbol_to_c_abi, list_with_capacity, pass_update_mode,
|
||||
};
|
||||
use crate::llvm::build_str::dec_to_str;
|
||||
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||
use crate::llvm::convert::{
|
||||
self, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout, zig_str_type,
|
||||
|
|
@ -65,7 +64,7 @@ use std::convert::TryInto;
|
|||
use std::path::Path;
|
||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||
|
||||
use super::convert::{zig_with_overflow_roc_dec, RocUnion};
|
||||
use super::convert::{zig_dec_type, zig_with_overflow_roc_dec, RocUnion};
|
||||
|
||||
#[inline(always)]
|
||||
fn print_fn_verification_output() -> bool {
|
||||
|
|
@ -5821,24 +5820,60 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
// Str.getScalarUnsafe : Str, Nat -> { bytesParsed : Nat, scalar : U32 }
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
let string = load_symbol(scope, &args[0]);
|
||||
let index = load_symbol(scope, &args[1]);
|
||||
|
||||
let result = call_str_bitcode_fn(
|
||||
env,
|
||||
&[string],
|
||||
&[index],
|
||||
BitcodeReturns::Basic,
|
||||
bitcode::STR_GET_SCALAR_UNSAFE,
|
||||
);
|
||||
match env.target_info.operating_system {
|
||||
Windows => {
|
||||
// we have to go digging to find the return type
|
||||
let function = env
|
||||
.module
|
||||
.get_function(bitcode::STR_GET_SCALAR_UNSAFE)
|
||||
.unwrap();
|
||||
|
||||
// on 32-bit platforms, zig bitpacks the struct
|
||||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes8 => result,
|
||||
PtrWidth::Bytes4 => {
|
||||
let to = basic_type_from_layout(env, layout);
|
||||
complex_bitcast_check_size(env, result, to, "to_roc_record")
|
||||
let return_type = function.get_type().get_param_types()[0]
|
||||
.into_pointer_type()
|
||||
.get_element_type()
|
||||
.into_struct_type();
|
||||
|
||||
let result = env.builder.build_alloca(return_type, "result");
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[result.into(), string, index],
|
||||
bitcode::STR_GET_SCALAR_UNSAFE,
|
||||
);
|
||||
|
||||
let return_type = basic_type_from_layout(env, layout);
|
||||
let cast_result = env.builder.build_pointer_cast(
|
||||
result,
|
||||
return_type.ptr_type(AddressSpace::Generic),
|
||||
"cast",
|
||||
);
|
||||
|
||||
env.builder.build_load(cast_result, "load_result")
|
||||
}
|
||||
Unix => {
|
||||
let result = call_str_bitcode_fn(
|
||||
env,
|
||||
&[string],
|
||||
&[index],
|
||||
BitcodeReturns::Basic,
|
||||
bitcode::STR_GET_SCALAR_UNSAFE,
|
||||
);
|
||||
|
||||
// on 32-bit platforms, zig bitpacks the struct
|
||||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes8 => result,
|
||||
PtrWidth::Bytes4 => {
|
||||
let to = basic_type_from_layout(env, layout);
|
||||
complex_bitcast_check_size(env, result, to, "to_roc_record")
|
||||
}
|
||||
}
|
||||
}
|
||||
Wasi => unimplemented!(),
|
||||
}
|
||||
}
|
||||
StrCountUtf8Bytes => {
|
||||
|
|
@ -7323,39 +7358,123 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
fn dec_split_into_words<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: IntValue<'ctx>,
|
||||
) -> (IntValue<'ctx>, IntValue<'ctx>) {
|
||||
let int_64 = env.context.i128_type().const_int(64, false);
|
||||
let int_64_type = env.context.i64_type();
|
||||
|
||||
let left_bits_i128 = env
|
||||
.builder
|
||||
.build_right_shift(value, int_64, false, "left_bits_i128");
|
||||
|
||||
(
|
||||
env.builder.build_int_cast(value, int_64_type, ""),
|
||||
env.builder.build_int_cast(left_bits_i128, int_64_type, ""),
|
||||
)
|
||||
}
|
||||
|
||||
fn dec_alloca<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let dec_type = zig_dec_type(env);
|
||||
|
||||
let alloca = env.builder.build_alloca(dec_type, "dec_alloca");
|
||||
|
||||
let instruction = alloca.as_instruction_value().unwrap();
|
||||
instruction.set_alignment(16).unwrap();
|
||||
|
||||
let ptr = env.builder.build_pointer_cast(
|
||||
alloca,
|
||||
value.get_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_to_i128_ptr",
|
||||
);
|
||||
|
||||
env.builder.build_store(ptr, value);
|
||||
|
||||
alloca
|
||||
}
|
||||
|
||||
fn dec_to_str<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
dec: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
let dec = dec.into_int_value();
|
||||
|
||||
match env.target_info.operating_system {
|
||||
Windows => {
|
||||
//
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[],
|
||||
&[dec_alloca(env, dec).into()],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::DEC_TO_STR,
|
||||
)
|
||||
}
|
||||
Unix => {
|
||||
let (low, high) = dec_split_into_words(env, dec);
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[],
|
||||
&[low.into(), high.into()],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::DEC_TO_STR,
|
||||
)
|
||||
}
|
||||
Wasi => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dec_binop_with_overflow<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
fn_name: &str,
|
||||
lhs: BasicValueEnum<'ctx>,
|
||||
rhs: BasicValueEnum<'ctx>,
|
||||
) -> StructValue<'ctx> {
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
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();
|
||||
match env.target_info.operating_system {
|
||||
Windows => {
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
return_alloca.into(),
|
||||
dec_alloca(env, lhs).into(),
|
||||
dec_alloca(env, rhs).into(),
|
||||
],
|
||||
fn_name,
|
||||
);
|
||||
}
|
||||
Unix => {
|
||||
let (lhs_low, lhs_high) = dec_split_into_words(env, lhs);
|
||||
let (rhs_low, rhs_high) = dec_split_into_words(env, rhs);
|
||||
|
||||
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,
|
||||
);
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
return_alloca.into(),
|
||||
lhs_low.into(),
|
||||
lhs_high.into(),
|
||||
rhs_low.into(),
|
||||
rhs_high.into(),
|
||||
],
|
||||
fn_name,
|
||||
);
|
||||
}
|
||||
Wasi => unimplemented!(),
|
||||
}
|
||||
|
||||
env.builder
|
||||
.build_load(return_alloca, "load_dec")
|
||||
|
|
@ -7368,29 +7487,37 @@ pub fn dec_binop_with_unchecked<'a, 'ctx, 'env>(
|
|||
lhs: BasicValueEnum<'ctx>,
|
||||
rhs: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
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();
|
||||
match env.target_info.operating_system {
|
||||
Windows => {
|
||||
// windows is much nicer for us here
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[dec_alloca(env, lhs).into(), dec_alloca(env, rhs).into()],
|
||||
fn_name,
|
||||
)
|
||||
}
|
||||
Unix => {
|
||||
let (lhs_low, lhs_high) = dec_split_into_words(env, lhs);
|
||||
let (rhs_low, rhs_high) = dec_split_into_words(env, rhs);
|
||||
|
||||
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,
|
||||
)
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
lhs_low.into(),
|
||||
lhs_high.into(),
|
||||
rhs_low.into(),
|
||||
rhs_high.into(),
|
||||
],
|
||||
fn_name,
|
||||
)
|
||||
}
|
||||
Wasi => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dec_binop<'a, 'ctx, 'env>(
|
||||
|
|
|
|||
|
|
@ -46,30 +46,6 @@ pub(crate) fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
/// Dec.toStr : Dec -> Str
|
||||
pub(crate) fn dec_to_str<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
dec: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec = dec.into_int_value();
|
||||
|
||||
let int_64 = env.context.i128_type().const_int(64, false);
|
||||
let int_64_type = env.context.i64_type();
|
||||
|
||||
let dec_right_shift = env
|
||||
.builder
|
||||
.build_right_shift(dec, int_64, false, "dec_left_bits");
|
||||
|
||||
let right_bits = env.builder.build_int_cast(dec, int_64_type, "");
|
||||
let left_bits = env.builder.build_int_cast(dec_right_shift, int_64_type, "");
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[],
|
||||
&[right_bits.into(), left_bits.into()],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::DEC_TO_STR,
|
||||
)
|
||||
}
|
||||
|
||||
/// Str.equal : Str, Str -> Bool
|
||||
pub(crate) fn str_equal<'a, 'ctx, 'env>(
|
||||
|
|
|
|||
|
|
@ -420,6 +420,10 @@ pub fn zig_str_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ct
|
|||
env.module.get_struct_type("str.RocStr").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_dec_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module.get_struct_type("dec.RocDec").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
let u8_ptr_t = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ fn tan() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn bitwise_and() {
|
||||
assert_evals_to!("Num.bitwiseAnd 20 20", 20, i64);
|
||||
assert_evals_to!("Num.bitwiseAnd 25 10", 8, i64);
|
||||
|
|
@ -1307,7 +1307,7 @@ fn bitwise_and() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn bitwise_xor() {
|
||||
assert_evals_to!("Num.bitwiseXor 20 20", 0, i64);
|
||||
assert_evals_to!("Num.bitwiseXor 15 14", 1, i64);
|
||||
|
|
@ -1316,7 +1316,7 @@ fn bitwise_xor() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn bitwise_or() {
|
||||
assert_evals_to!("Num.bitwiseOr 1 1", 1, i64);
|
||||
assert_evals_to!("Num.bitwiseOr 1 2", 3, i64);
|
||||
|
|
|
|||
|
|
@ -536,7 +536,7 @@ fn optional_field_let_no_use_default_nested() {
|
|||
{ x ? 10, y } = r
|
||||
x + y
|
||||
|
||||
f { x: 4, y: 9 }
|
||||
f { y: 9, x: 4 }
|
||||
"#
|
||||
),
|
||||
13,
|
||||
|
|
|
|||
|
|
@ -598,6 +598,14 @@ macro_rules! assert_llvm_evals_to {
|
|||
};
|
||||
}
|
||||
|
||||
// windows testing code
|
||||
// let mut target = target_lexicon::Triple::host();
|
||||
//
|
||||
// target.operating_system = target_lexicon::OperatingSystem::Windows;
|
||||
//
|
||||
// let (_main_fn_name, _delayed_errors, _module) =
|
||||
// $crate::helpers::llvm::create_llvm_module(&arena, $src, config, &context, &target);
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! assert_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty) => {{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ page_size = "0.4.2"
|
|||
winit = "0.26.0"
|
||||
wgpu = "0.12.0"
|
||||
wgpu_glyph = "0.16.0"
|
||||
glyph_brush = "0.7.2"
|
||||
glyph_brush = "0.7.5"
|
||||
log = "0.4.14"
|
||||
env_logger = "0.9.0"
|
||||
futures = "0.3.24"
|
||||
|
|
|
|||
|
|
@ -313,6 +313,8 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe
|
|||
* Plugin to translate linux commands like curl to Roc code
|
||||
* Plugin to view diff between two texts
|
||||
* Plugin to present codebase to new developer or walk co-worker through a problem. Records sequence of filenames and line numbers.
|
||||
* A Logbook plugin. I've found that writing down steps and thoughts when you're implementing or debugging something can be really useful for later.
|
||||
If we make an integrated terminal, we can automatically add executed commands to this logbook. This plugin could have a publish button so you can produce useful "blogs" for others with minimal effort.
|
||||
|
||||
### Inspiration
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
app "rocLovesC"
|
||||
packages { pf: "main.roc" }
|
||||
packages { pf: "c-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
app "rocLovesRust"
|
||||
packages { pf: "main.roc" }
|
||||
packages { pf: "rust-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
app "rocLovesSwift"
|
||||
packages { pf: "main.roc" }
|
||||
packages { pf: "swift-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
app "rocLovesWebAssembly"
|
||||
packages { pf: "main.roc" }
|
||||
packages { pf: "web-assembly-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
app "rocLovesZig"
|
||||
packages { pf: "main.roc" }
|
||||
packages { pf: "zig-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
To run this website, first compile either of these identical apps:
|
||||
|
||||
```bash
|
||||
# Option A: Compile examples/platform-switching/web-assembly-platform/rocLovesWebAssembly.roc
|
||||
cargo run -- build --target=wasm32 examples/platform-switching/web-assembly-platform/rocLovesWebAssembly.roc
|
||||
# Option A: Compile examples/platform-switching/rocLovesWebAssembly.roc
|
||||
cargo run -- build --target=wasm32 examples/platform-switching/rocLovesWebAssembly.roc
|
||||
|
||||
# Option B: Compile examples/platform-switching/main.roc with `pf: "web-assembly-platform/main.roc"` and move the result
|
||||
cargo run -- build --target=wasm32 examples/platform-switching/main.roc
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@
|
|||
|
||||
```sh
|
||||
# Note: If you installed Rust in this terminal session, you'll need to open a new one first!
|
||||
./roc examples/platform-switching/rust-platform/rocLovesRust.roc
|
||||
./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
./roc examples/platform-switching/zig-platform/rocLovesZig.roc
|
||||
./roc examples/platform-switching/rocLovesZig.roc
|
||||
|
||||
./roc examples/platform-switching/c-platform/rocLovesC.roc
|
||||
./roc examples/platform-switching/rocLovesC.roc
|
||||
```
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@
|
|||
|
||||
```sh
|
||||
# Note: If you installed rust in this terminal session, you'll need to open a new one first!
|
||||
./roc examples/platform-switching/rust-platform/rocLovesRust.roc
|
||||
./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
./roc examples/platform-switching/zig-platform/rocLovesZig.roc
|
||||
./roc examples/platform-switching/rocLovesZig.roc
|
||||
|
||||
./roc examples/platform-switching/c-platform/rocLovesC.roc
|
||||
./roc examples/platform-switching/rocLovesC.roc
|
||||
```
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@
|
|||
|
||||
```sh
|
||||
# Note: If you installed rust in this terminal session, you'll need to open a new one first!
|
||||
./roc examples/platform-switching/rust-platform/rocLovesRust.roc
|
||||
./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
./roc examples/platform-switching/zig-platform/rocLovesZig.roc
|
||||
./roc examples/platform-switching/rocLovesZig.roc
|
||||
|
||||
./roc examples/platform-switching/c-platform/rocLovesC.roc
|
||||
./roc examples/platform-switching/rocLovesC.roc
|
||||
```
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
1. Run examples:
|
||||
|
||||
```sh
|
||||
cargo run examples/platform-switching/rust-platform/rocLovesRust.roc
|
||||
cargo run examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
# This requires installing the Zig compiler, too.
|
||||
cargo run examples/platform-switching/zig-platform/rocLovesZig.roc
|
||||
cargo run examples/platform-switching/rocLovesZig.roc
|
||||
|
||||
# This requires installing the `clang` C compiler, too.
|
||||
cargo run examples/platform-switching/c-platform/rocLovesC.roc
|
||||
cargo run examples/platform-switching/rocLovesC.roc
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
[files]
|
||||
extend-exclude = ["crates/vendor/", "examples/static-site-gen/input/"]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue