Skip to content

feat(simd_avx2): add U8x32 — native AVX2 byte vector (round-3 keystone) #276

feat(simd_avx2): add U8x32 — native AVX2 byte vector (round-3 keystone)

feat(simd_avx2): add U8x32 — native AVX2 byte vector (round-3 keystone) #276

Workflow file for this run

on:
pull_request:
paths-ignore:
- '.github/workflows/latest-deps.yaml'
merge_group:
push:
branches:
- master
- main
name: Continuous integration
env:
CARGO_TERM_COLOR: always
HOST: x86_64-unknown-linux-gnu
FEATURES: "approx,serde,rayon"
# `-C target-cpu=x86-64-v3` was removed from the global env. It conflicts
# with the cross_test matrix (`i686-unknown-linux-gnu` is 32-bit, `s390x`
# isn't even x86) and contradicts the design intent recorded in
# `.cargo/config.toml`: per-function `#[target_feature]` + runtime
# `LazyLock<Tier>` detection means one binary, all ISAs. Jobs that
# specifically need a higher target-cpu can opt in via per-job env.
RUSTFLAGS: "-D warnings"
MSRV: 1.94.0
BLAS_MSRV: 1.94.0
jobs:
pass-msrv:
runs-on: ubuntu-latest
name: Pass MSRV values to other jobs
outputs:
MSRV: ${{ env.MSRV }}
BLAS_MSRV: ${{ env.BLAS_MSRV }}
steps:
- name: Pass MSRV
run: |
echo "MSRV=${{ env.MSRV }}" >> $GITHUB_OUTPUT
echo "BLAS_MSRV=${{ env.BLAS_MSRV }}" >> $GITHUB_OUTPUT
clippy:
runs-on: ubuntu-latest
strategy:
matrix:
# Pinned to 1.94.1 to match `rust-toolchain.toml`. Auto-tracking
# `stable` would silently bump to 1.95 and start rejecting code
# on lints like `clippy::unnecessary_sort_by` that 1.94 accepted.
rust:
- "1.94.1"
name: clippy/${{ matrix.rust }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.94.1
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --features approx,serde,rayon -- -D warnings
- run: cargo clippy --features native -- -D warnings
format:
runs-on: ubuntu-latest
name: format/nightly
# Marked non-blocking until a separate fmt-sweep PR aligns the
# codebase with `rustfmt.toml`. Local audit (2026-04-30) under
# `cargo +nightly fmt --all -- --check` reports 5,679 drift sites —
# too large to bundle into a CI-fix PR. The format job remains in
# the pipeline as a continuous signal so the sweep author can verify
# zero drift after running `cargo +nightly fmt --all`, but it does
# not gate merge until that sweep lands.
continue-on-error: true
steps:
- uses: actions/checkout@v4
# `rustfmt.toml` declares 13 nightly-only options
# (`brace_style = AlwaysNextLine`, `imports_granularity = Preserve`,
# `unstable_features = true`, etc.). Stable rustfmt warns and
# ignores them, then produces drift on every nightly-formatted
# file because its defaults differ from the unstable settings.
# The format job MUST use nightly rustfmt for the project's chosen
# style to be enforceable.
#
# The compile + clippy jobs stay on 1.94.1 (pinned in
# `rust-toolchain.toml`) — only this fmt job needs nightly.
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- run: cargo fmt --all --check
nostd:
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental }}
strategy:
matrix:
include:
- rust: stable
experimental: false
target: thumbv6m-none-eabi
name: nostd/${{ matrix.target }}/${{ matrix.rust }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
# rust-toolchain.toml pins 1.94.1 — install the cross-compile target
# for that toolchain too, since dtolnay/rust-toolchain only installs
# for the matrix value which may differ from the pinned version.
- run: rustup target add ${{ matrix.target }}
- name: Tests
run: |
# Scope to `-p ndarray` so workspace dev-deps (criterion → serde_core
# → getrandom) don't get evaluated against the no_std target. The
# library itself builds cleanly under no_std + portable-atomic-
# critical-section; only its dev-dependency tree pulls std-requiring
# crates that have no business existing in the nostd build.
cargo rustc -p ndarray "--target=${{ matrix.target }}" --no-default-features --features portable-atomic-critical-section
tests:
runs-on: ubuntu-latest
needs: pass-msrv
strategy:
matrix:
rust:
- stable
- beta
- ${{ needs.pass-msrv.outputs.MSRV }}
name: tests/${{ matrix.rust }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: rui314/setup-mold@v1
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- name: Install openblas
run: sudo apt-get install libopenblas-dev gfortran
- run: ./scripts/all-tests.sh "$FEATURES" ${{ matrix.rust }}
native-backend:
runs-on: ubuntu-latest
name: native-backend/stable
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- name: Build native backend
run: cargo build --features native
- name: Test native backend
run: cargo nextest run -p ndarray --features native
- name: Test native + approx
run: cargo nextest run -p ndarray --features native,approx
blas-msrv:
runs-on: ubuntu-latest
name: blas-msrv
needs: pass-msrv
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ needs.pass-msrv.outputs.BLAS_MSRV }}
- uses: rui314/setup-mold@v1
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- name: Install openblas
run: sudo apt-get install libopenblas-dev gfortran
- run: ./scripts/blas-integ-tests.sh $BLAS_MSRV
miri:
# Nightly-only. Cannot run SIMD intrinsics or FFI.
# Only runs on merge queue / push to main — never blocks PR checks.
if: github.event_name == 'merge_group' || github.event_name == 'push'
runs-on: ubuntu-latest
name: miri
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: miri
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- run: ./scripts/miri-tests.sh
cross_test:
# Gated on merge_group only — cross-compile via docker (cross-rs) for
# s390x / i686 is slow, flaky on the s390x docker image's toolchain
# resolution (rust-toolchain.toml's 1.94.1 pin doesn't resolve cleanly
# inside the s390x cross container), and reliably caught by the
# `tests/{stable,beta,1.94.0}` jobs on every PR push. Reserve cross
# validation for the merge queue where it can fail loudly without
# gating individual PRs on infra flakiness. The commented `if:` was
# the original intent (per the pre-existing comment) — uncommenting
# per the PR #143 codex thread that surfaced this consistently.
if: ${{ github.event_name == 'merge_group' }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- rust: stable
target: s390x-unknown-linux-gnu
- rust: stable
target: i686-unknown-linux-gnu
name: cross_test/${{ matrix.target }}/${{ matrix.rust }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
- uses: rui314/setup-mold@v1
- uses: Swatinem/rust-cache@v2
- name: Install cross
run: cargo install cross
- run: ./scripts/cross-tests.sh "approx,serde,rayon" ${{ matrix.rust }} ${{ matrix.target }}
cargo-careful:
# Nightly-only. Only runs on merge queue / push — never blocks PR checks.
if: github.event_name == 'merge_group' || github.event_name == 'push'
runs-on: ubuntu-latest
name: cargo-careful
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@nextest
- name: Install cargo-careful
run: cargo install cargo-careful
- run: cargo careful nextest run -Zcareful-sanitizer --features="$FEATURES"
docs:
# Nightly needed for --cfg docsrs. Only on merge queue / push.
if: github.event_name == 'merge_group' || github.event_name == 'push'
runs-on: ubuntu-latest
name: docs/nightly
env:
RUSTDOCFLAGS: "-Dwarnings --cfg docsrs"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: cargo doc --no-deps --all-features
conclusion:
needs:
- clippy
- format
- nostd
- tests
- native-backend
- miri
- cross_test
- cargo-careful
- docs
runs-on: ubuntu-latest
steps:
- name: Result
run: |
jq -C <<< "${needs}"
# Check if all needs were successful or skipped.
"$(jq -r 'all(.result as $result | (["success", "skipped"] | contains([$result])))' <<< "${needs}")"
env:
needs: ${{ toJson(needs) }}