Skip to content
Open
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
9 changes: 8 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,16 @@ jobs:
- aarch64_be-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
- loongarch64-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
- riscv32gc-unknown-linux-gnu
- x86_64-unknown-linux-gnu
profile: [dev, release]
cc: [clang, gcc]
include:
- target: aarch64_be-unknown-linux-gnu
build_std: true
- target: riscv32gc-unknown-linux-gnu
build_std: true
- target: x86_64-unknown-linux-gnu
cc: icx
profile: dev
Expand Down Expand Up @@ -322,7 +326,7 @@ jobs:
# Check that the generated files agree with the checked-in versions.
check-stdarch-gen:
needs: [style]
name: Check stdarch-gen-{arm, loongarch, hexagon} output
name: Check stdarch-gen-{arm, loongarch, hexagon, riscv} output
runs-on: ubuntu-latest
env:
STDARCH_GEN_MODE: check
Expand All @@ -342,6 +346,9 @@ jobs:
- name: Check hexagon
run: |
cargo run -p stdarch-gen-hexagon --release
- name: Check riscv
run: |
cargo run -p stdarch-gen-riscv --release

# Run some tests with Miri. Most stdarch functions use platform-specific intrinsics
# that Miri does not support. Also Miri is reltively slow.
Expand Down
26 changes: 18 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions ci/docker/riscv32gc-unknown-linux-gnu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ RUN wget "https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/
-O riscv-toolchain.tar.xz
RUN tar -xJf riscv-toolchain.tar.xz

RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz
RUN mkdir llvm
RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm

ENV CLANG_PATH="/llvm/bin/clang"
ENV GCC_PATH=/riscv/bin/riscv32-unknown-linux-gnu-gcc

ENV CARGO_TARGET_RISCV32GC_UNKNOWN_LINUX_GNU_LINKER=/riscv/bin/riscv32-unknown-linux-gnu-gcc \
CARGO_TARGET_RISCV32GC_UNKNOWN_LINUX_GNU_RUNNER="qemu-riscv32 -cpu max -L /riscv/sysroot" \
OBJDUMP=llvm-objdump
9 changes: 8 additions & 1 deletion ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ FROM ubuntu:25.10
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libc6-dev qemu-user ca-certificates \
gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \
llvm
llvm wget

RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz
RUN mkdir llvm
RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm

ENV CLANG_PATH="/llvm/bin/clang"
ENV GCC_PATH=riscv64-linux-gnu-gcc

ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc \
CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER="qemu-riscv64 -cpu max -L /usr/riscv64-linux-gnu" \
Expand Down
20 changes: 20 additions & 0 deletions ci/intrinsic-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ case ${TARGET} in
ARCH=loongarch64
RUNTIME_RUSTFLAGS=-Ctarget-feature=+lsx,+lasx,+frecipe
;;

riscv64*)
export CFLAGS="-I/usr/riscv64-linux-gnu/include/"
ARCH=riscv64
RUNTIME_RUSTFLAGS=
;;

riscv32*)
export CFLAGS="-I/riscv/sysroot/usr/include --sysroot=/riscv/sysroot"
ARCH=riscv32
RUNTIME_RUSTFLAGS=
;;

*)
;;

Expand All @@ -94,6 +107,13 @@ case "${TARGET}" in
--target "${TARGET}" \
--cc-arg-style "${CC_ARG_STYLE}"
;;
riscv*)
cargo run "${INTRINSIC_TEST}" --release \
--bin intrinsic-test -- crates/stdarch-gen-riscv \
--skip "crates/intrinsic-test/missing_riscv_common.txt" \
--target "${TARGET}" \
--cc-arg-style "${CC_ARG_STYLE}"
;;
*)
cargo run "${INTRINSIC_TEST}" --release \
--bin intrinsic-test -- intrinsics_data/arm_intrinsics.json \
Expand Down
14 changes: 14 additions & 0 deletions crates/intrinsic-test/missing_riscv_common.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
clz_32
clz_64
ctz_32
ctz_64
cpop_32
cpop_64
ror_32
ror_64
rol_32
rol_64
rev8_32
rev8_64
brev8_32
brev8_64
2 changes: 1 addition & 1 deletion crates/intrinsic-test/src/arm/json_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn json_to_intrinsic(
arguments,
results: result_ty,
arch_tags: intr.architectures,
extension: intr.simd_isa,
extensions: vec![intr.simd_isa],
})
}

Expand Down
4 changes: 2 additions & 2 deletions crates/intrinsic-test/src/arm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,12 @@ impl SupportedArchitecture for Arm {
// Skip A64-specific intrinsics on A32
.filter(|i| !(a32 && i.arch_tags == vec!["A64".to_string()]))
// Skip SVE intrinsics on big endian
.filter(|i| !(big_endian && (i.extension == "SVE" || i.extension == "SVE2")))
.filter(|i| !(big_endian && (i.extensions[0] == "SVE" || i.extensions[0] == "SVE2")))
// Skip SVE intrinsics when testing against GCC as our wrappers run into ICEs
// See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125818>
.filter(|i| {
!(matches!(cli_options.cc_arg_style, CcArgStyle::Gcc)
&& (i.extension == "SVE" || i.extension == "SVE2"))
&& (i.extensions[0] == "SVE" || i.extensions[0] == "SVE2"))
})
.take(sample_size)
.collect::<Vec<_>>();
Expand Down
4 changes: 2 additions & 2 deletions crates/intrinsic-test/src/common/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ pub struct Intrinsic<A: SupportedArchitecture> {
/// Any architecture-specific tags.
pub arch_tags: Vec<String>,

/// Specific extension that the intrinsic is from
pub extension: String,
/// Specific extension(s) that the intrinsic is from
pub extensions: Vec<String>,
}

impl<A: SupportedArchitecture> Intrinsic<A> {
Expand Down
2 changes: 1 addition & 1 deletion crates/intrinsic-test/src/loongarch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl SupportedArchitecture for LoongArch {
if self
.intrinsics
.iter()
.any(|intrinsic| intrinsic.extension == "LASX")
.any(|intrinsic| intrinsic.extensions[0] == "LASX")
{
flags.push("-mlasx");
}
Expand Down
2 changes: 1 addition & 1 deletion crates/intrinsic-test/src/loongarch/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ fn parse_intrinsic(
arguments: ArgumentList { args: arguments },
results: result,
arch_tags: Vec::new(),
extension: extension_for(name)?.to_string(),
extensions: vec![extension_for(name)?.to_string()],
})
}

Expand Down
4 changes: 4 additions & 0 deletions crates/intrinsic-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ extern crate log;
mod arm;
mod common;
mod loongarch;
mod riscv;
mod x86;

use arm::Arm;
use common::SupportedArchitecture;
use common::cli::{Cli, ProcessedCli};
use loongarch::LoongArch;
use riscv::Riscv;
use x86::X86;

fn main() {
Expand All @@ -28,6 +30,8 @@ fn main() {
LoongArch::create(&processed_cli_options),
processed_cli_options,
)
} else if processed_cli_options.target.starts_with("riscv") {
run(Riscv::create(&processed_cli_options), processed_cli_options);
} else {
unimplemented!("Unsupported target {}", processed_cli_options.target)
}
Expand Down
19 changes: 19 additions & 0 deletions crates/intrinsic-test/src/riscv/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::common::intrinsic_helpers::IntrinsicType;
use std::ops::{Deref, DerefMut};

#[derive(Debug, Clone, PartialEq)]
pub struct RiscvIntrinsicType(pub IntrinsicType);

impl Deref for RiscvIntrinsicType {
type Target = IntrinsicType;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for RiscvIntrinsicType {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
104 changes: 104 additions & 0 deletions crates/intrinsic-test/src/riscv/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
mod intrinsic;
mod parser;
mod types;

use std::path::Path;

use crate::common::SupportedArchitecture;
use crate::common::cli::ProcessedCli;
use crate::common::intrinsic::Intrinsic;
use crate::common::intrinsic_helpers::TypeKind;
use crate::riscv::parser::get_intrinsics;
use intrinsic::RiscvIntrinsicType;

#[derive(PartialEq)]
pub struct Riscv {
intrinsics: Vec<Intrinsic<Riscv>>,
}

impl SupportedArchitecture for Riscv {
type Type = RiscvIntrinsicType;

fn intrinsics(&self) -> &[Intrinsic<Self>] {
&self.intrinsics
}

fn create(cli_options: &ProcessedCli) -> Self {
let rv32 = cli_options.target.starts_with("riscv32");

let mut intrinsics =
load_intrinsics(&cli_options.filename).expect("Error parsing input file");

intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
intrinsics.dedup_by(|a, b| {
a.name == b.name && a.results == b.results && a.arguments == b.arguments
});

let sample_percentage: usize = cli_options.sample_percentage as usize;
let sample_size = (intrinsics.len() * sample_percentage) / 100;

let intrinsics = intrinsics
.into_iter()
// Skip intrinsics that don't return a value.
.filter(|intrinsic| intrinsic.results.kind() != TypeKind::Void)
.filter(|intrinsic| !intrinsic.arguments.args.is_empty())
.filter(|intrinsic| !cli_options.skip.contains(&intrinsic.name))
.filter(|intrinsic| {
intrinsic.arch_tags.is_empty() || ((intrinsic.arch_tags[0] == "rv64") ^ rv32)
})
.take(sample_size)
.collect::<Vec<_>>();

Self { intrinsics }
}

const NOTICE: &str = r#"
// This is a transient test file, not intended for distribution. Some aspects of the
// test are derived from RISC-V specification files, published under the same license as the
// `intrinsic-test` crate.
"#;

const C_PRELUDE: &str = r#"
#include <riscv_bitmanip.h>
#include <riscv_crypto.h>
"#;

const RUST_PRELUDE: &str = RUST_PRELUDE;

const C_NAME_PREFIX: &str = "__riscv_";

fn c_compiler_flags(&self, cli_options: &ProcessedCli) -> Vec<&str> {
let arch_str = if cli_options.target.starts_with("riscv32") {
"-march=rv32gc_zbb_zbc_zk_zks"
} else {
"-march=rv64gc_zbb_zbc_zk_zks"
};
vec![arch_str]
}

fn predicate_function(_: u32) -> String {
unimplemented!("scalable vector intrinsics are currently unimplemented for RISC-V")
}
}

const RUST_PRELUDE: &str = r#"
#![feature(riscv_ext_intrinsics)]

#[cfg(target_arch = "riscv64")]
use core_arch::arch::riscv64::*;
#[cfg(target_arch = "riscv32")]
use core_arch::arch::riscv32::*;
"#;

fn load_intrinsics(path: &Path) -> Result<Vec<Intrinsic<Riscv>>, Box<dyn std::error::Error>> {
if path.is_dir() {
let mut intrinsics = Vec::new();
for spec in ["crypto.spec", "bitmanip.spec"] {
let spec_path = path.join(spec);
intrinsics.extend(get_intrinsics(&spec_path)?);
}
return Ok(intrinsics);
}

get_intrinsics(path)
}
Loading
Loading