Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ concurrency:

jobs:
build-linux-amd64:
name: Build Linux amd64
runs-on: ubuntu-latest
timeout-minutes: 45

Expand Down Expand Up @@ -69,7 +70,86 @@ jobs:
- name: Run Wave end-to-end tests
run: python3 tools/run_tests.py

build-linux-riscv64:
name: Build Linux riscv64
runs-on: ubuntu-24.04
timeout-minutes: 45

steps:
- uses: actions/checkout@v4

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.89.0

- name: Install LLVM 21 and RISC-V runtime tools
run: |
set -euo pipefail

sudo apt-get update
sudo apt-get install -y wget software-properties-common
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get install -y \
binutils-riscv64-linux-gnu \
gcc-riscv64-linux-gnu \
libc6-dev-riscv64-cross \
lld-21 \
qemu-user

echo "LLVM_SYS_211_PREFIX=/usr/lib/llvm-21" >> "$GITHUB_ENV"
echo "LLVM_CONFIG_PATH=/usr/lib/llvm-21/bin/llvm-config" >> "$GITHUB_ENV"
echo "/usr/lib/llvm-21/bin" >> "$GITHUB_PATH"

- name: Verify RISC-V toolchain
run: |
set -euo pipefail

llvm-config --version
ld.lld --version
riscv64-linux-gnu-gcc --version
riscv64-linux-gnu-readelf --version
qemu-riscv64 --version
test -f /usr/riscv64-linux-gnu/lib/crt1.o
test -f /usr/riscv64-linux-gnu/lib/libc.so
test -f /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1

- name: Run RISC-V contract tests
run: >-
cargo test --locked --test codegen_regressions riscv64_ --verbose

- name: Build release compiler with RISC-V backend
run: cargo build --locked --release --verbose

- name: Link and run Linux riscv64 binary
run: |
set -euo pipefail

riscv_sysroot=/usr/riscv64-linux-gnu
output_dir="$RUNNER_TEMP/wave-linux-riscv64"
binary="$output_dir/test2"
mkdir -p "$output_dir"

target/release/wavec build test/test2.wave \
--target riscv64-unknown-linux-gnu \
--sysroot "$riscv_sysroot" \
--out-dir "$output_dir"

test -x "$binary"
riscv64-linux-gnu-readelf -h "$binary" | tee "$RUNNER_TEMP/riscv64-elf-header.txt"
riscv64-linux-gnu-readelf -l "$binary" | tee "$RUNNER_TEMP/riscv64-program-headers.txt"

grep -Eq 'Machine:[[:space:]]+RISC-V' "$RUNNER_TEMP/riscv64-elf-header.txt"
grep -Eq 'Flags:[[:space:]]+0x5.*double-float ABI' "$RUNNER_TEMP/riscv64-elf-header.txt"
grep -Fq '/lib/ld-linux-riscv64-lp64d.so.1' "$RUNNER_TEMP/riscv64-program-headers.txt"

runtime_output="$(timeout --signal=TERM --kill-after=5s 30s \
qemu-riscv64 -L "$riscv_sysroot" "$binary")"
printf '%s\n' "$runtime_output"
test "$runtime_output" = 'Hello World'

build-macos-arm64:
name: Build macOS arm64
runs-on: macos-latest
timeout-minutes: 45

Expand Down Expand Up @@ -130,6 +210,7 @@ jobs:
run: python3 tools/run_tests.py

build-windows-amd64:
name: Build Windows amd64
runs-on: windows-latest
timeout-minutes: 60

Expand Down
17 changes: 17 additions & 0 deletions front/parser/src/arch/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This file is part of the Wave language project.
// Copyright (c) 2024–2026 Wave Foundation
// Copyright (c) 2024–2026 LunaStev and contributors
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
// AI TRAINING NOTICE: Prohibited without prior written permission. No use for machine learning or generative AI training, fine-tuning, distillation, embedding, or dataset creation.

pub(super) const NAME: &str = "aarch64";

pub(super) fn recognizes(value: &str) -> bool {
matches!(value, "aarch64" | "arm64")
}
70 changes: 70 additions & 0 deletions front/parser/src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// This file is part of the Wave language project.
// Copyright (c) 2024–2026 Wave Foundation
// Copyright (c) 2024–2026 LunaStev and contributors
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
// AI TRAINING NOTICE: Prohibited without prior written permission. No use for machine learning or generative AI training, fine-tuning, distillation, embedding, or dataset creation.

mod aarch64;
mod riscv64;
mod x86_64;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Architecture {
X86_64,
Aarch64,
Riscv64,
}

impl Architecture {
pub const fn name(self) -> &'static str {
match self {
Self::X86_64 => x86_64::NAME,
Self::Aarch64 => aarch64::NAME,
Self::Riscv64 => riscv64::NAME,
}
}

pub fn from_name(value: &str) -> Option<Self> {
let value = value.trim().to_ascii_lowercase();
if x86_64::recognizes(&value) {
Some(Self::X86_64)
} else if aarch64::recognizes(&value) {
Some(Self::Aarch64)
} else if riscv64::recognizes(&value) {
Some(Self::Riscv64)
} else {
None
}
}
}

pub fn canonical_name(value: &str) -> String {
Architecture::from_name(value)
.map(|arch| arch.name().to_string())
.unwrap_or_else(|| value.trim().to_ascii_lowercase())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn architecture_aliases_have_stable_canonical_names() {
for (input, expected) in [
("x86_64", "x86_64"),
("AMD64", "x86_64"),
("aarch64", "aarch64"),
("arm64", "aarch64"),
("riscv64", "riscv64"),
("unknown-arch", "unknown-arch"),
] {
assert_eq!(canonical_name(input), expected);
}
}
}
17 changes: 17 additions & 0 deletions front/parser/src/arch/riscv64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This file is part of the Wave language project.
// Copyright (c) 2024–2026 Wave Foundation
// Copyright (c) 2024–2026 LunaStev and contributors
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
// AI TRAINING NOTICE: Prohibited without prior written permission. No use for machine learning or generative AI training, fine-tuning, distillation, embedding, or dataset creation.

pub(super) const NAME: &str = "riscv64";

pub(super) fn recognizes(value: &str) -> bool {
value == NAME
}
17 changes: 17 additions & 0 deletions front/parser/src/arch/x86_64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This file is part of the Wave language project.
// Copyright (c) 2024–2026 Wave Foundation
// Copyright (c) 2024–2026 LunaStev and contributors
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
// AI TRAINING NOTICE: Prohibited without prior written permission. No use for machine learning or generative AI training, fine-tuning, distillation, embedding, or dataset creation.

pub(super) const NAME: &str = "x86_64";

pub(super) fn recognizes(value: &str) -> bool {
matches!(value, "x86_64" | "amd64")
}
7 changes: 2 additions & 5 deletions front/parser/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// SPDX-License-Identifier: MPL-2.0
// AI TRAINING NOTICE: Prohibited without prior written permission. No use for machine learning or generative AI training, fine-tuning, distillation, embedding, or dataset creation.

use crate::arch;
use crate::ast::ASTNode;
use crate::{parse_syntax_only, ParseError};
use error::error::{WaveError, WaveErrorKind};
Expand Down Expand Up @@ -74,11 +75,7 @@ impl<'a> TargetAttrCondition<'a> {
fn normalize_target_value(key: &str, value: &str) -> String {
let lower = value.trim().to_ascii_lowercase();
match key {
"arch" => match lower.as_str() {
"amd64" => "x86_64".to_string(),
"arm64" => "aarch64".to_string(),
other => other.to_string(),
},
"arch" => arch::canonical_name(&lower),
"os" => match lower.as_str() {
"darwin" | "apple" => "macos".to_string(),
"win32" | "win64" => "windows".to_string(),
Expand Down
1 change: 1 addition & 0 deletions front/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ macro_rules! println {
}};
}

pub mod arch;
pub mod ast;
pub mod expr;
pub mod format;
Expand Down
7 changes: 4 additions & 3 deletions llvm/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct BackendOptions {
pub cpu: Option<String>,
pub features: Option<String>,
pub abi: Option<String>,
pub isa: Option<String>,
pub code_model: Option<String>,
pub relocation_model: Option<String>,
pub sysroot: Option<String>,
Expand Down Expand Up @@ -175,10 +176,10 @@ fn append_lld_target_args(cmd: &mut Command, target: &str, backend: &BackendOpti
let spec = target_spec_for_triple(target)
.expect("Darwin linker configuration requires a registered target");
cmd.arg("-arch")
.arg(if spec.arch == "aarch64" {
.arg(if spec.architecture.name() == "aarch64" {
"arm64"
} else {
spec.arch
spec.architecture.name()
})
.arg("-platform_version")
.arg("macos")
Expand Down Expand Up @@ -231,7 +232,7 @@ fn elf_lld_emulation(target: &str) -> Option<&'static str> {
match target_spec_for_triple(target)?.codegen {
CodegenTarget::LinuxX86_64 | CodegenTarget::FreestandingX86_64 => Some("elf_x86_64"),
CodegenTarget::LinuxArm64 | CodegenTarget::FreestandingArm64 => Some("aarch64elf"),
CodegenTarget::FreestandingRISCV64 => Some("elf64lriscv"),
CodegenTarget::LinuxRISCV64 | CodegenTarget::FreestandingRISCV64 => Some("elf64lriscv"),
_ => None,
}
}
Expand Down
8 changes: 6 additions & 2 deletions llvm/src/codegen/abi_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,9 @@ fn classify_param<'ctx>(
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => classify_param_arm64_darwin(td, t),
CodegenTarget::FreestandingRISCV64 => classify_param_riscv64(td, t),
CodegenTarget::LinuxRISCV64 | CodegenTarget::FreestandingRISCV64 => {
classify_param_riscv64(td, t)
}
}
}

Expand All @@ -519,7 +521,9 @@ fn classify_ret<'ctx>(
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => classify_ret_arm64_darwin(td, t),
CodegenTarget::FreestandingRISCV64 => classify_ret_riscv64(td, t),
CodegenTarget::LinuxRISCV64 | CodegenTarget::FreestandingRISCV64 => {
classify_ret_riscv64(td, t)
}
}
}

Expand Down
Loading
Loading