Skip to content

Commit b0ff457

Browse files
eduardosmAmanieu
authored andcommitted
Remove some allow(unsafe_op_in_unsafe_fn)s and use target_feature 1.1 in examples
1 parent 1c6113f commit b0ff457

File tree

4 files changed

+111
-71
lines changed

4 files changed

+111
-71
lines changed

crates/std_detect/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#![feature(staged_api, doc_cfg, allow_internal_unstable)]
1919
#![deny(rust_2018_idioms)]
2020
#![allow(clippy::shadow_reuse)]
21-
#![allow(unsafe_op_in_unsafe_fn)]
2221
#![cfg_attr(test, allow(unused_imports))]
2322
#![no_std]
2423
#![allow(internal_features)]

examples/connect5.rs

+54-40
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
//! each move.
3030
3131
#![allow(internal_features)]
32-
#![allow(unsafe_op_in_unsafe_fn)]
3332
#![feature(avx512_target_feature)]
3433
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx512, stdarch_internal))]
3534
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx512, stdarch_internal))]
@@ -419,12 +418,12 @@ fn pos_is_draw(pos: &Pos) -> bool {
419418
found && !pos_is_winner(pos)
420419
}
421420

422-
#[target_feature(enable = "avx512f,avx512bw")]
421+
#[target_feature(enable = "avx512f,avx512bw,popcnt")]
423422
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
424-
unsafe fn pos_is_draw_avx512(pos: &Pos) -> bool {
423+
fn pos_is_draw_avx512(pos: &Pos) -> bool {
425424
let empty = Color::Empty as usize;
426425

427-
let board0org = _mm512_loadu_epi32(&pos.bitboard[empty][0][0]);
426+
let board0org = unsafe { _mm512_loadu_epi32(&pos.bitboard[empty][0][0]) };
428427

429428
let answer = _mm512_set1_epi32(0);
430429

@@ -481,7 +480,7 @@ fn search(pos: &Pos, alpha: i32, beta: i32, depth: i32, _ply: i32) -> i32 {
481480

482481
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
483482
{
484-
if is_x86_feature_detected!("avx512bw") {
483+
if check_x86_avx512_features() {
485484
unsafe {
486485
if pos_is_winner_avx512(pos) {
487486
return -EVAL_INF + _ply;
@@ -571,7 +570,7 @@ fn eval(pos: &Pos, _ply: i32) -> i32 {
571570
// check if opp has live4 which will win playing next move
572571
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
573572
{
574-
if is_x86_feature_detected!("avx512bw") {
573+
if check_x86_avx512_features() {
575574
unsafe {
576575
if check_patternlive4_avx512(pos, def) {
577576
return -4096;
@@ -594,7 +593,7 @@ fn eval(pos: &Pos, _ply: i32) -> i32 {
594593
// check if self has live4 which will win playing next move
595594
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
596595
{
597-
if is_x86_feature_detected!("avx512bw") {
596+
if check_x86_avx512_features() {
598597
unsafe {
599598
if check_patternlive4_avx512(pos, atk) {
600599
return 2560;
@@ -617,7 +616,7 @@ fn eval(pos: &Pos, _ply: i32) -> i32 {
617616
// check if self has dead4 which will win playing next move
618617
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
619618
{
620-
if is_x86_feature_detected!("avx512bw") {
619+
if check_x86_avx512_features() {
621620
unsafe {
622621
if check_patterndead4_avx512(pos, atk) > 0 {
623622
return 2560;
@@ -639,7 +638,7 @@ fn eval(pos: &Pos, _ply: i32) -> i32 {
639638

640639
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
641640
{
642-
if is_x86_feature_detected!("avx512bw") {
641+
if check_x86_avx512_features() {
643642
unsafe {
644643
let n_c4: i32 = check_patterndead4_avx512(pos, def);
645644
let n_c3: i32 = check_patternlive3_avx512(pos, def);
@@ -854,16 +853,18 @@ fn check_patternlive3(pos: &Pos, sd: Side) -> i32 {
854853
n
855854
}
856855

857-
#[target_feature(enable = "avx512f,avx512bw")]
856+
#[target_feature(enable = "avx512f,avx512bw,popcnt")]
858857
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
859-
unsafe fn pos_is_winner_avx512(pos: &Pos) -> bool {
858+
fn pos_is_winner_avx512(pos: &Pos) -> bool {
860859
let current_side = side_opp(pos.p_turn);
861860
let coloridx = current_side as usize;
862861

863-
let board0org: [__m512i; 2] = [
864-
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
865-
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
866-
]; // load states from bitboard
862+
let board0org: [__m512i; 2] = unsafe {
863+
[
864+
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
865+
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
866+
]
867+
}; // load states from bitboard
867868

868869
#[rustfmt::skip]
869870
let answer = _mm512_set1_epi16((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)); // an unbroken chain of five moves
@@ -928,9 +929,9 @@ unsafe fn pos_is_winner_avx512(pos: &Pos) -> bool {
928929
count_match > 0
929930
}
930931

931-
#[target_feature(enable = "avx512f,avx512bw")]
932+
#[target_feature(enable = "avx512f,avx512bw,popcnt")]
932933
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
933-
unsafe fn check_patternlive4_avx512(pos: &Pos, sd: Side) -> bool {
934+
fn check_patternlive4_avx512(pos: &Pos, sd: Side) -> bool {
934935
let coloridx = sd as usize;
935936
let emptyidx = Color::Empty as usize;
936937

@@ -952,14 +953,18 @@ unsafe fn check_patternlive4_avx512(pos: &Pos, sd: Side) -> bool {
952953
0b00_10_10_11_11_11_11_11_10_10_10_10_10_11_11_10,
953954
0b00_10_10_10_11_11_11_10_10_10_10_10_11_11_11_10,
954955
0b00_10_10_10_10_11_10_10_10_10_10_11_11_11_11_10];
955-
let board0org: [__m512i; 2] = [
956-
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
957-
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
958-
];
959-
let board1org: [__m512i; 2] = [
960-
_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]),
961-
_mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0]),
962-
];
956+
let board0org: [__m512i; 2] = unsafe {
957+
[
958+
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
959+
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
960+
]
961+
};
962+
let board1org: [__m512i; 2] = unsafe {
963+
[
964+
_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]),
965+
_mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0]),
966+
]
967+
};
963968

964969
let mut count_match: i32 = 0;
965970

@@ -990,9 +995,9 @@ unsafe fn check_patternlive4_avx512(pos: &Pos, sd: Side) -> bool {
990995
count_match > 0
991996
}
992997

993-
#[target_feature(enable = "avx512f,avx512bw")]
998+
#[target_feature(enable = "avx512f,avx512bw,popcnt")]
994999
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
995-
unsafe fn check_patterndead4_avx512(pos: &Pos, sd: Side) -> i32 {
1000+
fn check_patterndead4_avx512(pos: &Pos, sd: Side) -> i32 {
9961001
let coloridx = sd as usize;
9971002
let emptyidx = Color::Empty as usize;
9981003

@@ -1023,14 +1028,18 @@ unsafe fn check_patterndead4_avx512(pos: &Pos, sd: Side) -> i32 {
10231028
0b00_10_10_11_11_11_11_11_10_10_10_10_11_11_11_10,
10241029
0b00_10_10_10_11_11_11_10_10_10_10_11_11_11_11_10,
10251030
0b00_10_10_10_10_11_10_10_10_10_11_11_11_11_11_10];
1026-
let board0org: [__m512i; 2] = [
1027-
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
1028-
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
1029-
];
1030-
let board1org: [__m512i; 2] = [
1031-
_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]),
1032-
_mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0]),
1033-
];
1031+
let board0org: [__m512i; 2] = unsafe {
1032+
[
1033+
_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]),
1034+
_mm512_loadu_epi32(&pos.bitboard[coloridx][1][0]),
1035+
]
1036+
};
1037+
let board1org: [__m512i; 2] = unsafe {
1038+
[
1039+
_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]),
1040+
_mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0]),
1041+
]
1042+
};
10341043

10351044
let mut count_match: i32 = 0;
10361045

@@ -1063,16 +1072,16 @@ unsafe fn check_patterndead4_avx512(pos: &Pos, sd: Side) -> i32 {
10631072
count_match
10641073
}
10651074

1066-
#[target_feature(enable = "avx512f,avx512bw")]
1075+
#[target_feature(enable = "avx512f,avx512bw,popcnt")]
10671076
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1068-
unsafe fn check_patternlive3_avx512(pos: &Pos, sd: Side) -> i32 {
1077+
fn check_patternlive3_avx512(pos: &Pos, sd: Side) -> i32 {
10691078
let coloridx = sd as usize;
10701079
let emptyidx = Color::Empty as usize;
10711080

10721081
#[rustfmt::skip]
1073-
let board0org: [__m512i; 2] = [_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]), _mm512_loadu_epi32(&pos.bitboard[coloridx][1][0])];
1082+
let board0org: [__m512i; 2] = unsafe { [_mm512_loadu_epi32(&pos.bitboard[coloridx][0][0]), _mm512_loadu_epi32(&pos.bitboard[coloridx][1][0])] };
10741083
#[rustfmt::skip]
1075-
let board1org: [__m512i; 2] = [_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]), _mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0])];
1084+
let board1org: [__m512i; 2] = unsafe { [_mm512_loadu_epi32(&pos.bitboard[emptyidx][0][0]), _mm512_loadu_epi32(&pos.bitboard[emptyidx][1][0])] };
10761085

10771086
#[rustfmt::skip]
10781087
let answer_color: [__m512i; 1] = [_mm512_set1_epi16( (1<<14)|(1<<13)|(1<<12) )];
@@ -1170,10 +1179,15 @@ unsafe fn check_patternlive3_avx512(pos: &Pos, sd: Side) -> i32 {
11701179
count_match
11711180
}
11721181

1182+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1183+
fn check_x86_avx512_features() -> bool {
1184+
is_x86_feature_detected!("avx512bw") && is_x86_feature_detected!("popcnt")
1185+
}
1186+
11731187
fn main() {
11741188
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
11751189
{
1176-
if is_x86_feature_detected!("avx512bw") {
1190+
if check_x86_avx512_features() {
11771191
println!("\n\nThe program is running with avx512f and avx512bw intrinsics\n\n");
11781192
} else {
11791193
println!("\n\nThe program is running with NO intrinsics.\n\n");

examples/hex.rs

+46-22
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
clippy::cast_sign_loss,
3030
clippy::missing_docs_in_private_items
3131
)]
32-
#![allow(unsafe_op_in_unsafe_fn)]
3332

3433
use std::{
3534
io::{self, Read},
@@ -67,7 +66,7 @@ fn hex_encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
6766
#[cfg(target_arch = "wasm32")]
6867
{
6968
if true {
70-
return unsafe { hex_encode_simd128(src, dst) };
69+
return hex_encode_simd128(src, dst);
7170
}
7271
}
7372

@@ -76,15 +75,18 @@ fn hex_encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
7675

7776
#[target_feature(enable = "avx2")]
7877
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
79-
unsafe fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
78+
fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
79+
assert!(dst.len() >= src.len().checked_mul(2).unwrap());
80+
8081
let ascii_zero = _mm256_set1_epi8(b'0' as i8);
8182
let nines = _mm256_set1_epi8(9);
8283
let ascii_a = _mm256_set1_epi8((b'a' - 9 - 1) as i8);
8384
let and4bits = _mm256_set1_epi8(0xf);
8485

8586
let mut i = 0_usize;
8687
while src.len() >= 32 {
87-
let invec = _mm256_loadu_si256(src.as_ptr() as *const _);
88+
// SAFETY: the loop condition ensures that we have at least 32 bytes
89+
let invec = unsafe { _mm256_loadu_si256(src.as_ptr() as *const _) };
8890

8991
let masked1 = _mm256_and_si256(invec, and4bits);
9092
let masked2 = _mm256_and_si256(_mm256_srli_epi64(invec, 4), and4bits);
@@ -102,34 +104,43 @@ unsafe fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a s
102104
let res2 = _mm256_unpackhi_epi8(masked2, masked1);
103105

104106
// Store everything into the right destination now
105-
let base = dst.as_mut_ptr().add(i * 2);
106-
let base1 = base.add(0) as *mut _;
107-
let base2 = base.add(16) as *mut _;
108-
let base3 = base.add(32) as *mut _;
109-
let base4 = base.add(48) as *mut _;
110-
_mm256_storeu2_m128i(base3, base1, res1);
111-
_mm256_storeu2_m128i(base4, base2, res2);
107+
unsafe {
108+
// SAFETY: the assertion at the beginning of the function ensures
109+
// that `dst` is large enough.
110+
let base = dst.as_mut_ptr().add(i * 2);
111+
let base1 = base.add(0) as *mut _;
112+
let base2 = base.add(16) as *mut _;
113+
let base3 = base.add(32) as *mut _;
114+
let base4 = base.add(48) as *mut _;
115+
_mm256_storeu2_m128i(base3, base1, res1);
116+
_mm256_storeu2_m128i(base4, base2, res2);
117+
}
118+
112119
src = &src[32..];
113120
i += 32;
114121
}
115122

116123
let _ = hex_encode_sse41(src, &mut dst[i * 2..]);
117124

118-
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
125+
// SAFETY: `dst` only contains ASCII characters
126+
unsafe { Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) }
119127
}
120128

121129
// copied from https://github.com/Matherunner/bin2hex-sse/blob/master/base16_sse4.cpp
122130
#[target_feature(enable = "sse4.1")]
123131
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
124-
unsafe fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
132+
fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
133+
assert!(dst.len() >= src.len().checked_mul(2).unwrap());
134+
125135
let ascii_zero = _mm_set1_epi8(b'0' as i8);
126136
let nines = _mm_set1_epi8(9);
127137
let ascii_a = _mm_set1_epi8((b'a' - 9 - 1) as i8);
128138
let and4bits = _mm_set1_epi8(0xf);
129139

130140
let mut i = 0_usize;
131141
while src.len() >= 16 {
132-
let invec = _mm_loadu_si128(src.as_ptr() as *const _);
142+
// SAFETY: the loop condition ensures that we have at least 16 bytes
143+
let invec = unsafe { _mm_loadu_si128(src.as_ptr() as *const _) };
133144

134145
let masked1 = _mm_and_si128(invec, and4bits);
135146
let masked2 = _mm_and_si128(_mm_srli_epi64(invec, 4), and4bits);
@@ -146,20 +157,27 @@ unsafe fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a
146157
let res1 = _mm_unpacklo_epi8(masked2, masked1);
147158
let res2 = _mm_unpackhi_epi8(masked2, masked1);
148159

149-
_mm_storeu_si128(dst.as_mut_ptr().add(i * 2) as *mut _, res1);
150-
_mm_storeu_si128(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2);
160+
unsafe {
161+
// SAFETY: the assertion at the beginning of the function ensures
162+
// that `dst` is large enough.
163+
_mm_storeu_si128(dst.as_mut_ptr().add(i * 2) as *mut _, res1);
164+
_mm_storeu_si128(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2);
165+
}
151166
src = &src[16..];
152167
i += 16;
153168
}
154169

155170
let _ = hex_encode_fallback(src, &mut dst[i * 2..]);
156171

157-
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
172+
// SAFETY: `dst` only contains ASCII characters
173+
unsafe { Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) }
158174
}
159175

160176
#[cfg(target_arch = "wasm32")]
161177
#[target_feature(enable = "simd128")]
162-
unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
178+
fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
179+
assert!(dst.len() >= src.len().checked_mul(2).unwrap());
180+
163181
use core_arch::arch::wasm32::*;
164182

165183
let ascii_zero = u8x16_splat(b'0');
@@ -169,7 +187,8 @@ unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'
169187

170188
let mut i = 0_usize;
171189
while src.len() >= 16 {
172-
let invec = v128_load(src.as_ptr() as *const _);
190+
// SAFETY: the loop condition ensures that we have at least 16 bytes
191+
let invec = unsafe { v128_load(src.as_ptr() as *const _) };
173192

174193
let masked1 = v128_and(invec, and4bits);
175194
let masked2 = v128_and(u8x16_shr(invec, 4), and4bits);
@@ -193,15 +212,20 @@ unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'
193212
masked2, masked1,
194213
);
195214

196-
v128_store(dst.as_mut_ptr().add(i * 2) as *mut _, res1);
197-
v128_store(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2);
215+
unsafe {
216+
// SAFETY: the assertion at the beginning of the function ensures
217+
// that `dst` is large enough.
218+
v128_store(dst.as_mut_ptr().add(i * 2) as *mut _, res1);
219+
v128_store(dst.as_mut_ptr().add(i * 2 + 16) as *mut _, res2);
220+
}
198221
src = &src[16..];
199222
i += 16;
200223
}
201224

202225
let _ = hex_encode_fallback(src, &mut dst[i * 2..]);
203226

204-
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
227+
// SAFETY: `dst` only contains ASCII characters
228+
unsafe { Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2])) }
205229
}
206230

207231
fn hex_encode_fallback<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {

0 commit comments

Comments
 (0)