diff --git a/Cargo.lock b/Cargo.lock index 60e11a35..bc8d3367 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "cinder" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "atomic", diff --git a/Cargo.toml b/Cargo.toml index 6645e11e..5575ce1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cinder" -version = "0.6.0" +version = "0.6.1" authors = ["Bruno Dutra "] edition = "2024" description = "A hobby chess engine" diff --git a/Makefile b/Makefile index 5d9a86ea..add9f595 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CRATE_VERSION := 0.6.0 +CRATE_VERSION := 0.6.1 TARGET_DIR := $(CURDIR)/target BIN_DIR := $(TARGET_DIR)/bin diff --git a/README.md b/README.md index 6e083c04..f627c39b 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Cinder is distributed under the terms of the GPL-3.0 license, see [LICENSE] for [Leela Chess Zero]: https://lczero.org/ [Open Database License]: https://opendatacommons.org/licenses/odbl/1-0/ -[v0.6.*]: https://github.com/brunocodutra/cinder/releases/tag/v0.6.0 +[v0.6.*]: https://github.com/brunocodutra/cinder/releases/tag/v0.6.1 [v0.5.*]: https://github.com/brunocodutra/cinder/releases/tag/v0.5.2 [v0.4.*]: https://github.com/brunocodutra/cinder/releases/tag/v0.4.1 [v0.3.*]: https://github.com/brunocodutra/cinder/releases/tag/v0.3.1 diff --git a/lib/chess/pins.rs b/lib/chess/pins.rs index 6453560c..bbfb8f18 100644 --- a/lib/chess/pins.rs +++ b/lib/chess/pins.rs @@ -35,16 +35,15 @@ impl Pins { }; } - let piece_mask = board.squares()[turn].to_simd().find( + let pins = furled.mask(pinned).extend().mask(beyond).unfurl(rays); + let pinned = board.squares()[turn].to_simd().find( rays.compress(pinned.to_bitmask()).extract::<0, 16>(), pinned.count().cast(), ); - let pinned = furled.mask(pinned).extend().mask(beyond).unfurl(rays); - Pins { - attacks: threats[turn] & (u16x64::splat(!piece_mask) | pinned.to_idx_set()), - unpinned: !pinned.occupied(), + attacks: threats[turn] & (u16x64::splat(!pinned) | pins.to_idx_set()), + unpinned: !pins.occupied(), } } diff --git a/lib/chess/placement.rs b/lib/chess/placement.rs index f5c4f00c..a1ea1b21 100644 --- a/lib/chess/placement.rs +++ b/lib/chess/placement.rs @@ -635,21 +635,21 @@ impl Placement { #[cfg(target_feature = "avx512f")] { - let idx_set = u16x64::splat(1).shlv(indices.cast::()); - indices.simd_ne(zeroed()).select(idx_set, zeroed()) + let ones = self.occupied().select(Simd::splat(1), Simd::splat(0)); + ones.shlv(indices.cast::()) } #[cfg(not(target_feature = "avx512f"))] unsafe { #[rustfmt::skip] const S0: u8x64 = Simd::from_array([ - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]); @@ -665,9 +665,9 @@ impl Placement { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ]); - transmute_copy::<(u8x64, u8x64), u16x64>( - &S0.shuffle(indices).interleave(S1.shuffle(indices)), - ) + let (left, right) = S0.shuffle(indices).interleave(S1.shuffle(indices)); + let indices = transmute_copy::<[u8x64; 2], u16x64>(&[left, right]); + self.occupied().select(indices, zeroed()) } } diff --git a/lib/simd/shlv.rs b/lib/simd/shlv.rs index 24b2a000..1e21d7dc 100644 --- a/lib/simd/shlv.rs +++ b/lib/simd/shlv.rs @@ -1,5 +1,5 @@ -use crate::{simd::Halve, util::Num}; -use std::simd::prelude::*; +use crate::util::{Assume, Num}; +use std::{array, simd::prelude::*}; /// Trait for [`Simd<_, _>` ] types that can shift left dynamically. pub trait Shlv { @@ -7,136 +7,13 @@ pub trait Shlv { fn shlv(self, shift: Self) -> Self; } -impl Shlv for u16x64 { +impl Shlv for Simd { #[inline(always)] #[cfg_attr(feature = "no_panic", no_panic::no_panic)] fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - let [x0, x1] = self.halve(); - let [s0, s1] = shift.halve(); - Halve::merge([x0.shlv(s0), x1.shlv(s1)]) - } -} - -impl Shlv for u16x32 { - #[inline(always)] - #[cfg(target_feature = "avx512bw")] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - use std::arch::x86_64::*; - _mm512_sllv_epi16(self.into(), shift.into()).into() - } - } - - #[inline(always)] - #[cfg(not(target_feature = "avx512bw"))] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - let [x0, x1] = self.halve(); - let [s0, s1] = shift.halve(); - Halve::merge([x0.shlv(s0), x1.shlv(s1)]) - } -} - -impl Shlv for u16x16 { - #[inline(always)] - #[cfg(all(target_feature = "avx512bw", target_feature = "avx512vl"))] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - use std::arch::x86_64::*; - _mm256_sllv_epi16(self.into(), shift.into()).into() - } - } - - #[inline(always)] - #[cfg(not(all(target_feature = "avx512bw", target_feature = "avx512vl")))] - #[cfg(target_feature = "avx2")] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - use std::arch::x86_64::*; - - let x0 = _mm256_unpacklo_epi16(Simd::splat(0).into(), self.into()); - let x1 = _mm256_unpackhi_epi16(Simd::splat(0).into(), self.into()); - let s0 = _mm256_unpacklo_epi16(shift.into(), Simd::splat(0).into()); - let s1 = _mm256_unpackhi_epi16(shift.into(), Simd::splat(0).into()); - let r0 = _mm256_srli_epi32(_mm256_sllv_epi32(x0, s0), 16); - let r1 = _mm256_srli_epi32(_mm256_sllv_epi32(x1, s1), 16); - _mm256_packus_epi32(r0, r1).into() - } - } - - #[inline(always)] - #[cfg(not(all(target_feature = "avx512bw", target_feature = "avx512vl")))] - #[cfg(not(target_feature = "avx2"))] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - let [x0, x1] = self.halve(); - let [s0, s1] = shift.halve(); - Halve::merge([x0.shlv(s0), x1.shlv(s1)]) - } -} - -impl Shlv for u16x8 { - #[inline(always)] - #[cfg(all(target_feature = "avx512bw", target_feature = "avx512vl"))] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - use std::arch::x86_64::*; - _mm_sllv_epi16(self.into(), shift.into()).into() - } - } - - #[inline(always)] - #[cfg(target_feature = "neon")] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - use std::arch::aarch64::*; - vshlq_u16(self.into(), vreinterpretq_s16_u16(shift.into())).into() - } - } - - #[inline(always)] - #[cfg(not(all(target_feature = "avx512bw", target_feature = "avx512vl")))] - #[cfg(not(target_feature = "neon"))] - #[cfg_attr(feature = "no_panic", no_panic::no_panic)] - fn shlv(self, shift: Self) -> Self { - fallback(self, shift) - } -} - -#[allow(unused)] -#[inline(always)] -#[cfg_attr(feature = "no_panic", no_panic::no_panic)] -fn fallback(x: u16x8, shift: u16x8) -> u16x8 { - debug_assert!(shift.simd_lt(Simd::splat(16)).all()); - - unsafe { - u16x8::from_array([ - x[0].unchecked_shl(shift[0].cast()), - x[1].unchecked_shl(shift[1].cast()), - x[2].unchecked_shl(shift[2].cast()), - x[3].unchecked_shl(shift[3].cast()), - x[4].unchecked_shl(shift[4].cast()), - x[5].unchecked_shl(shift[5].cast()), - x[6].unchecked_shl(shift[6].cast()), - x[7].unchecked_shl(shift[7].cast()), - ]) + Simd::from_array(array::from_fn(|i| { + self[i].checked_shl(shift[i].cast()).assume() + })) } } @@ -191,6 +68,9 @@ mod tests { #[strategy(UniformArrayStrategy::new(0u16..=255u16).prop_map(u16x8::from_array))] x: u16x8, #[strategy(UniformArrayStrategy::new(0u16..8u16).prop_map(u16x8::from_array))] s: u16x8, ) { - assert_eq!(x.shlv(s), fallback(x, s)); + use crate::simd::Halve; + let [x0, x1] = x.halve(); + let [s0, s1] = s.halve(); + assert_eq!(x.shlv(s).halve(), [x0.shlv(s0), x1.shlv(s1)]); } }