diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 9f389d8b4..534a80ea7 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -94,10 +94,18 @@ jobs: test_verbatim: 1 - target: i686-pc-windows-gnu os: windows-2025 - channel: nightly-i686-gnu + channel: nightly-2025-04-29-i686-gnu - target: x86_64-pc-windows-gnu os: windows-2025 - channel: nightly-x86_64-gnu + channel: nightly-2025-04-29-x86_64-gnu + - target: sbpf-solana-solana + os: ubuntu-24.04 + - target: sbpfv1-solana-solana + os: ubuntu-24.04 + - target: sbpfv2-solana-solana + os: ubuntu-24.04 + - target: sbpfv3-solana-solana + os: ubuntu-24.04 runs-on: ${{ matrix.os }} needs: [calculate_vars] env: @@ -111,14 +119,22 @@ jobs: with: submodules: true - name: Install Rust (rustup) + if: ${{ !startsWith(matrix.target, 'sbpf') }} shell: bash run: | - channel="nightly" + channel="nightly-2025-04-29" # Account for channels that have required components (MinGW) [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" rustup update "$channel" --no-self-update rustup default "$channel" rustup target add "${{ matrix.target }}" + - name: Install Rust (rustup) + if: ${{ startsWith(matrix.target, 'sbpf') }} + shell: bash + run: | + channel="nightly-2025-04-29" + rustup update "$channel" --no-self-update + rustup default "$channel" - uses: taiki-e/install-action@nextest - uses: Swatinem/rust-cache@v2 with: @@ -188,7 +204,7 @@ jobs: - name: Install nightly `clippy` run: | rustup set profile minimal - rustup default nightly + rustup default nightly-2025-04-29 rustup component add clippy - uses: Swatinem/rust-cache@v2 - run: cargo clippy --workspace --all-targets @@ -259,7 +275,7 @@ jobs: with: submodules: true - name: Install Rust (rustup) - run: rustup update nightly --no-self-update && rustup default nightly + run: rustup update nightly-2025-04-29 --no-self-update && rustup default nightly-2025-04-29 shell: bash - run: rustup component add miri - run: cargo miri setup diff --git a/builtins-test-intrinsics/Cargo.toml b/builtins-test-intrinsics/Cargo.toml index 704de20c5..103a97546 100644 --- a/builtins-test-intrinsics/Cargo.toml +++ b/builtins-test-intrinsics/Cargo.toml @@ -17,3 +17,10 @@ panic = "abort" [profile.dev] panic = "abort" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(target_family, values("solana"))', + 'cfg(target_feature, values("static-syscalls"))', + 'cfg(target_os, values("solana"))' +] } \ No newline at end of file diff --git a/builtins-test-intrinsics/src/main.rs b/builtins-test-intrinsics/src/main.rs index 66744a081..41dcf1816 100644 --- a/builtins-test-intrinsics/src/main.rs +++ b/builtins-test-intrinsics/src/main.rs @@ -17,8 +17,12 @@ extern crate compiler_builtins; extern crate panic_handler; -// SAFETY: no definitions, only used for linking -#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))] +#[cfg(all( + not(thumb), + not(windows), + not(target_arch = "wasm32"), + not(target_os = "solana") +))] #[link(name = "c")] unsafe extern "C" {} diff --git a/builtins-test/Cargo.toml b/builtins-test/Cargo.toml index 10978c0bb..a7f0cb8ba 100644 --- a/builtins-test/Cargo.toml +++ b/builtins-test/Cargo.toml @@ -22,9 +22,12 @@ default-features = false features = ["unstable-public-internals"] [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } paste = "1.0.15" +[target.'cfg(not(target_arch = "sbf"))'.dev-dependencies] +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } + + [target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] test = { git = "https://github.com/japaric/utest" } utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } @@ -50,7 +53,7 @@ no-sys-f16 = ["no-sys-f16-f64-convert"] icount = ["dep:iai-callgrind"] # Enable report generation without bringing in more dependencies by default -benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] +# benchmarking-reports = ["criterion/plotters", "criterion/html_reports"] # NOTE: benchmarks must be run with `--no-default-features` or with # `-p builtins-test`, otherwise the default `compiler-builtins` feature @@ -97,3 +100,11 @@ harness = false name = "mem_icount" harness = false required-features = ["icount"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(target_family, values("solana"))', + 'cfg(target_feature, values("static-syscalls"))', + 'cfg(target_os, values("solana"))' +] } + diff --git a/builtins-test/tests/conv.rs b/builtins-test/tests/conv.rs index 491915d9b..0822c66c7 100644 --- a/builtins-test/tests/conv.rs +++ b/builtins-test/tests/conv.rs @@ -84,7 +84,9 @@ mod i_to_f { if !Float::eq_repr(f0, f1) && !cfg!(any( target_arch = "x86", target_arch = "powerpc", - target_arch = "powerpc64" + target_arch = "powerpc64", + // In SBF, the rounding bug exists when ALU32 is disbaled. + not(target_feature = "static-syscalls"), )) { panic!( "{}({}): std: {:?}, builtins: {:?}", diff --git a/builtins-test/tests/div_rem.rs b/builtins-test/tests/div_rem.rs index 5ae653cc9..26744f1ba 100644 --- a/builtins-test/tests/div_rem.rs +++ b/builtins-test/tests/div_rem.rs @@ -138,7 +138,10 @@ macro_rules! float { }; } -#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] +#[cfg(not(any( + all(target_arch = "x86", not(target_feature = "sse")), + target_family = "solana" +)))] mod float_div { use super::*; diff --git a/builtins-test/tests/mem.rs b/builtins-test/tests/mem.rs index d838ef159..9a54e87e1 100644 --- a/builtins-test/tests/mem.rs +++ b/builtins-test/tests/mem.rs @@ -37,6 +37,7 @@ fn memcpy_10() { } } +#[cfg(not(target_os = "solana"))] #[test] fn memcpy_big() { // Make the arrays cross 3 pages @@ -165,6 +166,7 @@ fn memmove_forward_misaligned_nonaligned_start() { } } +#[cfg(not(target_os = "solana"))] #[test] fn memmove_forward_misaligned_aligned_start() { let mut arr = gen_arr::<32>(); diff --git a/ci/docker/sbpf-solana-solana/Dockerfile b/ci/docker/sbpf-solana-solana/Dockerfile new file mode 100644 index 000000000..6c9807aa0 --- /dev/null +++ b/ci/docker/sbpf-solana-solana/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:22.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + gcc libc6-dev ca-certificates bzip2 \ + libssl-dev pkg-config + +ENV RUSTUP_INIT_SKIP_PATH_CHECK="yes" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -v --no-modify-path +RUN cp ${HOME}/.cargo/bin/* /usr/local/bin/ + +RUN cargo install --git https://github.com/anza-xyz/cargo-run-solana-tests.git \ + --rev ccfb0a3f5f967f3cf52fef0c95e283c7cab1836e \ + --bin cargo-run-solana-tests --root /usr/local + +RUN mkdir -p /tmp/.cache/solana/v1.51/platform-tools +RUN curl -L -o platform-tools-linux-x86_64.tar.bz2 https://github.com/anza-xyz/platform-tools/releases/download/v1.51/platform-tools-linux-x86_64.tar.bz2 +RUN tar -xjf platform-tools-linux-x86_64.tar.bz2 --strip-components 1 -C /tmp/.cache/solana/v1.51/platform-tools +RUN rustup toolchain link solana /tmp/.cache/solana/v1.51/platform-tools/rust +RUN cp -R ${HOME}/.rustup /tmp/ + +ENV CARGO_TARGET_SBPF_SOLANA_SOLANA_RUNNER="cargo-run-solana-tests --heap-size 104857600" +ENV LLVM_HOME="/tmp/.cache/solana/v1.51/platform-tools/llvm" +ENV CC="/tmp/.cache/solana/v1.51/platform-tools/llvm/bin/clang" +ENV RUSTUP_TOOLCHAIN="solana" diff --git a/ci/docker/sbpfv1-solana-solana/Dockerfile b/ci/docker/sbpfv1-solana-solana/Dockerfile new file mode 100644 index 000000000..030639e52 --- /dev/null +++ b/ci/docker/sbpfv1-solana-solana/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:22.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + gcc libc6-dev ca-certificates bzip2 \ + libssl-dev pkg-config + +ENV RUSTUP_INIT_SKIP_PATH_CHECK="yes" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -v --no-modify-path +RUN cp ${HOME}/.cargo/bin/* /usr/local/bin/ + +RUN cargo install --git https://github.com/anza-xyz/cargo-run-solana-tests.git \ + --rev ccfb0a3f5f967f3cf52fef0c95e283c7cab1836e \ + --bin cargo-run-solana-tests --root /usr/local + +RUN mkdir -p /tmp/.cache/solana/v1.51/platform-tools +RUN curl -L -o platform-tools-linux-x86_64.tar.bz2 https://github.com/anza-xyz/platform-tools/releases/download/v1.51/platform-tools-linux-x86_64.tar.bz2 +RUN tar -xjf platform-tools-linux-x86_64.tar.bz2 --strip-components 1 -C /tmp/.cache/solana/v1.51/platform-tools +RUN rustup toolchain link solana /tmp/.cache/solana/v1.51/platform-tools/rust +RUN cp -R ${HOME}/.rustup /tmp/ + +ENV CARGO_TARGET_SBPFV1_SOLANA_SOLANA_RUNNER="cargo-run-solana-tests --heap-size 104857600" +ENV LLVM_HOME="/tmp/.cache/solana/v1.51/platform-tools/llvm" +ENV CC="/tmp/.cache/solana/v1.51/platform-tools/llvm/bin/clang" +ENV RUSTUP_TOOLCHAIN="solana" diff --git a/ci/docker/sbpfv2-solana-solana/Dockerfile b/ci/docker/sbpfv2-solana-solana/Dockerfile new file mode 100644 index 000000000..dd3489a82 --- /dev/null +++ b/ci/docker/sbpfv2-solana-solana/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:22.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + gcc libc6-dev ca-certificates bzip2 \ + libssl-dev pkg-config + +ENV RUSTUP_INIT_SKIP_PATH_CHECK="yes" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -v --no-modify-path +RUN cp ${HOME}/.cargo/bin/* /usr/local/bin/ + +RUN cargo install --git https://github.com/anza-xyz/cargo-run-solana-tests.git \ + --rev ccfb0a3f5f967f3cf52fef0c95e283c7cab1836e \ + --bin cargo-run-solana-tests --root /usr/local + +RUN mkdir -p /tmp/.cache/solana/v1.51/platform-tools +RUN curl -L -o platform-tools-linux-x86_64.tar.bz2 https://github.com/anza-xyz/platform-tools/releases/download/v1.51/platform-tools-linux-x86_64.tar.bz2 +RUN tar -xjf platform-tools-linux-x86_64.tar.bz2 --strip-components 1 -C /tmp/.cache/solana/v1.51/platform-tools +RUN rustup toolchain link solana /tmp/.cache/solana/v1.51/platform-tools/rust +RUN cp -R ${HOME}/.rustup /tmp/ + +ENV CARGO_TARGET_SBPFV2_SOLANA_SOLANA_RUNNER="cargo-run-solana-tests --heap-size 104857600" +ENV LLVM_HOME="/tmp/.cache/solana/v1.51/platform-tools/llvm" +ENV CC="/tmp/.cache/solana/v1.51/platform-tools/llvm/bin/clang" +ENV RUSTUP_TOOLCHAIN="solana" diff --git a/ci/docker/sbpfv3-solana-solana/Dockerfile b/ci/docker/sbpfv3-solana-solana/Dockerfile new file mode 100644 index 000000000..bf67af987 --- /dev/null +++ b/ci/docker/sbpfv3-solana-solana/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:22.04 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + gcc libc6-dev ca-certificates bzip2 \ + libssl-dev pkg-config + +ENV RUSTUP_INIT_SKIP_PATH_CHECK="yes" +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -v --no-modify-path +RUN cp ${HOME}/.cargo/bin/* /usr/local/bin/ + +RUN cargo install --git https://github.com/anza-xyz/cargo-run-solana-tests.git \ + --rev ccfb0a3f5f967f3cf52fef0c95e283c7cab1836e \ + --bin cargo-run-solana-tests --root /usr/local + +RUN mkdir -p /tmp/.cache/solana/v1.51/platform-tools +RUN curl -L -o platform-tools-linux-x86_64.tar.bz2 https://github.com/anza-xyz/platform-tools/releases/download/v1.51/platform-tools-linux-x86_64.tar.bz2 +RUN tar -xjf platform-tools-linux-x86_64.tar.bz2 --strip-components 1 -C /tmp/.cache/solana/v1.51/platform-tools +RUN rustup toolchain link solana /tmp/.cache/solana/v1.51/platform-tools/rust +RUN cp -R ${HOME}/.rustup /tmp/ + +ENV CARGO_TARGET_SBPFV3_SOLANA_SOLANA_RUNNER="cargo-run-solana-tests --heap-size 104857600" +ENV LLVM_HOME="/tmp/.cache/solana/v1.51/platform-tools/llvm" +ENV CC="/tmp/.cache/solana/v1.51/platform-tools/llvm/bin/clang" +ENV RUSTUP_TOOLCHAIN="solana" diff --git a/ci/run.sh b/ci/run.sh index 27b9686ea..d280df192 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -30,16 +30,27 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then echo "no tests to run for build-only targets" else test_builtins=(cargo test --package builtins-test --no-fail-fast --target "$target") - "${test_builtins[@]}" + if [[ ! "$target" =~ ^sbf && ! "$target" =~ ^sbpf- ]]; then + # Not using release mode causes a stack overflow in SBPFv0 + # There is a bug in SBPFv3 whereby we were not adding returns to -O0 code + "${test_builtins[@]}" + "${test_builtins[@]}" --features c + "${test_builtins[@]}" --features no-asm + "${test_builtins[@]}" --features no-f16-f128 + fi + "${test_builtins[@]}" --release - "${test_builtins[@]}" --features c "${test_builtins[@]}" --features c --release - "${test_builtins[@]}" --features no-asm "${test_builtins[@]}" --features no-asm --release - "${test_builtins[@]}" --features no-f16-f128 "${test_builtins[@]}" --features no-f16-f128 --release - "${test_builtins[@]}" --benches - "${test_builtins[@]}" --benches --release + + if [[ ! "$target" =~ ^sbf && ! "$target" =~ ^sbpf ]]; then + # Benches require criterion, which is not compatible with SBPF + "${test_builtins[@]}" --benches + "${test_builtins[@]}" --benches --release + "${test_builtins[@]}" --benches + "${test_builtins[@]}" --benches --release + fi if [ "${TEST_VERBATIM:-}" = "1" ]; then verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2) diff --git a/compiler-builtins/Cargo.toml b/compiler-builtins/Cargo.toml index 8ceef286f..71b467c11 100644 --- a/compiler-builtins/Cargo.toml +++ b/compiler-builtins/Cargo.toml @@ -61,4 +61,11 @@ unstable-public-internals = [] [lints.rust] # The cygwin config can be dropped after our benchmark toolchain is bumped -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] } +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(bootstrap)', + 'cfg(target_os, values("cygwin"))', + 'cfg(target_family, values("solana"))', + 'cfg(target_feature, values("static-syscalls"))', + 'cfg(target_os, values("solana"))' +] } + diff --git a/compiler-builtins/build.rs b/compiler-builtins/build.rs index d37fdc5df..893d1d2de 100644 --- a/compiler-builtins/build.rs +++ b/compiler-builtins/build.rs @@ -52,6 +52,7 @@ fn main() { || target.arch.contains("x86") || target.arch.contains("aarch64") || target.arch.contains("bpf") + || target.arch.contains("sbf") { println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); } @@ -609,6 +610,10 @@ mod c { sources.extend(&[("__emutls_get_address", "emutls.c")]); } + if target.os == "solana" { + cfg.define("__ELF__", None); + } + // When compiling the C code we require the user to tell us where the // source code is, and this is largely done so when we're compiling as // part of rust-lang/rust we can use the same llvm-project repository as diff --git a/compiler-builtins/src/lib.rs b/compiler-builtins/src/lib.rs index 6a6b28067..05863bd6b 100644 --- a/compiler-builtins/src/lib.rs +++ b/compiler-builtins/src/lib.rs @@ -4,10 +4,12 @@ #![feature(asm_experimental_arch)] #![feature(cfg_target_has_atomic)] #![feature(compiler_builtins)] +#![cfg_attr(not(target_os = "solana"), feature(core_ffi_c))] #![feature(core_intrinsics)] #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(isqrt)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] diff --git a/compiler-builtins/src/mem/mod.rs b/compiler-builtins/src/mem/mod.rs index 6828f3804..7df580700 100644 --- a/compiler-builtins/src/mem/mod.rs +++ b/compiler-builtins/src/mem/mod.rs @@ -11,12 +11,14 @@ type c_int = i16; type c_int = i32; // memcpy/memmove/memset have optimized implementations on some architectures +#[cfg(not(target_os = "solana"))] #[cfg_attr( all(not(feature = "no-asm"), target_arch = "x86_64"), path = "x86_64.rs" )] mod impls; +#[cfg(not(target_os = "solana"))] intrinsics! { #[mem_builtin] pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { @@ -58,3 +60,94 @@ intrinsics! { impls::c_string_length(s) } } + +// MEM functions have been rewritten to copy 8 byte chunks. No +// compensation for alignment is made here with the requirement that +// the underlying hardware supports unaligned loads/stores. If the +// number of store operations is greater than 8 the memory operation +// is performed in the run-time system instead, by calling the +// corresponding "C" function. +#[cfg(all(target_os = "solana", not(target_feature = "static-syscalls")))] +mod syscalls { + extern "C" { + pub fn sol_memcpy_(dest: *mut u8, src: *const u8, n: u64); + pub fn sol_memmove_(dest: *mut u8, src: *const u8, n: u64); + pub fn sol_memset_(s: *mut u8, c: u8, n: u64); + pub fn sol_memcmp_(s1: *const u8, s2: *const u8, n: u64, result: *mut i32); + } +} + +#[cfg(all(target_os = "solana", target_feature = "static-syscalls"))] +mod syscalls { + pub(crate) fn sol_memcpy_(dest: *mut u8, src: *const u8, n: u64) { + let syscall: extern "C" fn(*mut u8, *const u8, u64) = + unsafe { core::mem::transmute(1904002211u64) }; // murmur32 hash of "sol_memcpy_" + syscall(dest, src, n) + } + + pub(crate) fn sol_memmove_(dest: *mut u8, src: *const u8, n: u64) { + let syscall: extern "C" fn(*mut u8, *const u8, u64) = + unsafe { core::mem::transmute(1128493560u64) }; // murmur32 hash of "sol_memmove_" + syscall(dest, src, n) + } + + pub(crate) fn sol_memcmp_(dest: *const u8, src: *const u8, n: u64, result: *mut i32) { + let syscall: extern "C" fn(*const u8, *const u8, u64, *mut i32) = + unsafe { core::mem::transmute(1608310321u64) }; // murmur32 hash of "sol_memcmp_" + syscall(dest, src, n, result) + } + + pub(crate) fn sol_memset_(dest: *mut u8, c: u8, n: u64) { + let syscall: extern "C" fn(*mut u8, u8, u64) = + unsafe { core::mem::transmute(930151202u64) }; // murmur32 hash of "sol_memset_" + syscall(dest, c, n) + } +} + +#[cfg(target_os = "solana")] +use self::syscalls::*; + +#[cfg(target_os = "solana")] +#[cfg_attr( + all(feature = "mem-unaligned", not(feature = "mangled-names")), + no_mangle +)] +#[inline] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + sol_memcpy_(dest, src, n as u64); + dest +} + +#[cfg(target_os = "solana")] +#[cfg_attr( + all(feature = "mem-unaligned", not(feature = "mangled-names")), + no_mangle +)] +#[inline] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + sol_memmove_(dest, src, n as u64); + dest +} + +#[cfg(target_os = "solana")] +#[cfg_attr( + all(feature = "mem-unaligned", not(feature = "mangled-names")), + no_mangle +)] +#[inline] +pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 { + sol_memset_(s, c as u8, n as u64); + s +} + +#[cfg(target_os = "solana")] +#[cfg_attr( + all(feature = "mem-unaligned", not(feature = "mangled-names")), + no_mangle +)] +#[inline] +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + let mut result = 0; + sol_memcmp_(s1, s2, n as u64, &mut result as *mut i32); + result +}