Files
gcc/libgrust/rustc-lib/stdarch/examples/hex.rs
Owen Avery b65abf4b39 gccrs: Import stdarch 1.49.0
This commit imports stdarch 1.49.0 into libgrust/rustc-lib/stdarch. This
is necessary for compiling libcore, as libcore attempts to reuse some
files from stdarch.

libgrust/ChangeLog:

	* rustc-lib/stdarch/.cirrus.yml: New file.
	* rustc-lib/stdarch/.github/workflows/main.yml: New file.
	* rustc-lib/stdarch/.gitignore: New file.
	* rustc-lib/stdarch/CONTRIBUTING.md: New file.
	* rustc-lib/stdarch/Cargo.toml: New file.
	* rustc-lib/stdarch/LICENSE-APACHE: New file.
	* rustc-lib/stdarch/LICENSE-MIT: New file.
	* rustc-lib/stdarch/README.md: New file.
	* rustc-lib/stdarch/ci/android-install-ndk.sh: New file.
	* rustc-lib/stdarch/ci/android-install-sdk.sh: New file.
	* rustc-lib/stdarch/ci/android-sysimage.sh: New file.
	* rustc-lib/stdarch/ci/docker/aarch64-linux-android/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/arm-linux-androideabi/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/i586-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/i686-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/mips-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/mipsel-unknown-linux-musl/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/nvptx64-nvidia-cuda/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/powerpc-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/s390x-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/wasm32-wasi/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/x86_64-linux-android/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/x86_64-unknown-linux-gnu-emulated/Dockerfile: New file.
	* rustc-lib/stdarch/ci/docker/x86_64-unknown-linux-gnu/Dockerfile: New file.
	* rustc-lib/stdarch/ci/dox.sh: New file.
	* rustc-lib/stdarch/ci/gba.json: New file.
	* rustc-lib/stdarch/ci/run-docker.sh: New file.
	* rustc-lib/stdarch/ci/run.sh: New file.
	* rustc-lib/stdarch/ci/runtest-android.rs: New file.
	* rustc-lib/stdarch/ci/style.sh: New file.
	* rustc-lib/stdarch/crates/assert-instr-macro/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/assert-instr-macro/build.rs: New file.
	* rustc-lib/stdarch/crates/assert-instr-macro/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/core_arch/LICENSE-APACHE: New file.
	* rustc-lib/stdarch/crates/core_arch/LICENSE-MIT: New file.
	* rustc-lib/stdarch/crates/core_arch/README.md: New file.
	* rustc-lib/stdarch/crates/core_arch/avx512f.md: New file.
	* rustc-lib/stdarch/crates/core_arch/build.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/rustfmt.toml: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/crc.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/crypto.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/neon/generated.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/neon/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/prefetch.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/test_support.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/tme.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/aarch64/v8.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/barrier/common.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/barrier/cp15.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/barrier/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/barrier/not_mclass.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/barrier/v8.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/dsp.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/ex.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/hints.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/registers/aarch32.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/registers/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/registers/v6m.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/registers/v7m.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/sat.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/acle/simd32.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/armclang.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/crc.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/neon/generated.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/neon/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/neon/table_lookup_tests.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/test_support.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/v6.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/arm/v7.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/core_arch_docs.md: New file.
	* rustc-lib/stdarch/crates/core_arch/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/macros.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/mips/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/mips/msa.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/mips/msa/macros.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/nvptx/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/powerpc/altivec.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/powerpc/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/powerpc/vsx.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/powerpc64/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/simd.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/simd_llvm.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/v64.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/wasm32/atomic.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/wasm32/memory.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/wasm32/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/wasm32/simd128.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/abm.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/adx.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/aes.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/avx.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/avx2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/avx512f.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/avx512ifma.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/bmi1.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/bmi2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/bswap.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/bt.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/cpuid.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/eflags.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/f16c.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/fma.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/fxsr.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/macros.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/pclmulqdq.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/rdrand.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/rdtsc.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/rtm.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sha.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse3.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse41.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse42.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/sse4a.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/ssse3.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/tbm.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/test.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86/xsave.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/abm.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/adx.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/avx.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/avx2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/avx512f.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/bmi.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/bmi2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/bswap.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/bt.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/cmpxchg16b.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/fxsr.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/mod.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/rdrand.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/sse.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/sse2.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/sse41.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/sse42.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/src/x86_64/xsave.rs: New file.
	* rustc-lib/stdarch/crates/core_arch/tests/cpu-detection.rs: New file.
	* rustc-lib/stdarch/crates/simd-test-macro/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/simd-test-macro/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/std_detect/LICENSE-APACHE: New file.
	* rustc-lib/stdarch/crates/std_detect/LICENSE-MIT: New file.
	* rustc-lib/stdarch/crates/std_detect/README.md: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/aarch64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/arm.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/mips.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/mips64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/powerpc.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/arch/x86.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/bit.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/cache.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/error_macros.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/macros.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/mod.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/aarch64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/freebsd/aarch64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/freebsd/arm.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/freebsd/auxvec.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/freebsd/mod.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/freebsd/powerpc.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/arm.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/cpuinfo.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/mips.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/mod.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/linux/powerpc.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/other.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/windows/aarch64.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/os/x86.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/test_data/linux-rpi3.auxv: New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/test_data/linux-x64-i7-6850k.auxv:
	New file.
	* rustc-lib/stdarch/crates/std_detect/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv:
	New file.
	* rustc-lib/stdarch/crates/std_detect/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/src/mod.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/tests/cpu-detection.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/tests/macro_trailing_commas.rs: New file.
	* rustc-lib/stdarch/crates/std_detect/tests/x86-specific.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-gen/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/stdarch-gen/README.md: New file.
	* rustc-lib/stdarch/crates/stdarch-gen/neon.spec: New file.
	* rustc-lib/stdarch/crates/stdarch-gen/src/main.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-test/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/stdarch-test/src/disassembly.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-test/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-test/src/wasm.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/.gitattributes: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/Cargo.toml: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/arm-intrinsics.html: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/build.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/mips-msa.h: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/src/lib.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/tests/arm.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/tests/mips.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/tests/x86-intel.rs: New file.
	* rustc-lib/stdarch/crates/stdarch-verify/x86-intel.xml: New file.
	* rustc-lib/stdarch/examples/Cargo.toml: New file.
	* rustc-lib/stdarch/examples/hex.rs: New file.
	* rustc-lib/stdarch/examples/wasm.rs: New file.
	* rustc-lib/stdarch/triagebot.toml: New file.
	* rustc-lib/stdarch/vendor.yml: New file.

Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
2025-10-30 21:30:46 +01:00

403 lines
13 KiB
Rust

//! An example showing runtime dispatch to an architecture-optimized
//! implementation.
//!
//! This program implements hex encoding a slice into a predetermined
//! destination using various different instruction sets. This selects at
//! runtime the most optimized implementation and uses that rather than being
//! required to be compiled differently.
//!
//! You can test out this program via:
//!
//! echo test | cargo +nightly run --release hex
//!
//! and you should see `746573740a` get printed out.
#![feature(stdsimd, wasm_target_feature)]
#![cfg_attr(test, feature(test))]
#![cfg_attr(target_arch = "wasm32", feature(wasm_simd))]
#![allow(
clippy::result_unwrap_used,
clippy::print_stdout,
clippy::option_unwrap_used,
clippy::shadow_reuse,
clippy::cast_possible_wrap,
clippy::cast_ptr_alignment,
clippy::cast_sign_loss,
clippy::missing_docs_in_private_items
)]
use std::{
io::{self, Read},
str,
};
#[cfg(target_arch = "x86")]
use {core_arch::arch::x86::*, std_detect::is_x86_feature_detected};
#[cfg(target_arch = "x86_64")]
use {core_arch::arch::x86_64::*, std_detect::is_x86_feature_detected};
fn main() {
let mut input = Vec::new();
io::stdin().read_to_end(&mut input).unwrap();
let mut dst = vec![0; 2 * input.len()];
let s = hex_encode(&input, &mut dst).unwrap();
println!("{}", s);
}
fn hex_encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
let len = src.len().checked_mul(2).unwrap();
if dst.len() < len {
return Err(len);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
if is_x86_feature_detected!("avx2") {
return unsafe { hex_encode_avx2(src, dst) };
}
if is_x86_feature_detected!("sse4.1") {
return unsafe { hex_encode_sse41(src, dst) };
}
}
#[cfg(target_arch = "wasm32")]
{
if true {
return unsafe { hex_encode_simd128(src, dst) };
}
}
hex_encode_fallback(src, dst)
}
#[target_feature(enable = "avx2")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe fn hex_encode_avx2<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
let ascii_zero = _mm256_set1_epi8(b'0' as i8);
let nines = _mm256_set1_epi8(9);
let ascii_a = _mm256_set1_epi8((b'a' - 9 - 1) as i8);
let and4bits = _mm256_set1_epi8(0xf);
let mut i = 0_isize;
while src.len() >= 32 {
let invec = _mm256_loadu_si256(src.as_ptr() as *const _);
let masked1 = _mm256_and_si256(invec, and4bits);
let masked2 = _mm256_and_si256(_mm256_srli_epi64(invec, 4), and4bits);
// return 0xff corresponding to the elements > 9, or 0x00 otherwise
let cmpmask1 = _mm256_cmpgt_epi8(masked1, nines);
let cmpmask2 = _mm256_cmpgt_epi8(masked2, nines);
// add '0' or the offset depending on the masks
let masked1 = _mm256_add_epi8(masked1, _mm256_blendv_epi8(ascii_zero, ascii_a, cmpmask1));
let masked2 = _mm256_add_epi8(masked2, _mm256_blendv_epi8(ascii_zero, ascii_a, cmpmask2));
// interleave masked1 and masked2 bytes
let res1 = _mm256_unpacklo_epi8(masked2, masked1);
let res2 = _mm256_unpackhi_epi8(masked2, masked1);
// Store everything into the right destination now
let base = dst.as_mut_ptr().offset(i * 2);
let base1 = base.offset(0) as *mut _;
let base2 = base.offset(16) as *mut _;
let base3 = base.offset(32) as *mut _;
let base4 = base.offset(48) as *mut _;
_mm256_storeu2_m128i(base3, base1, res1);
_mm256_storeu2_m128i(base4, base2, res2);
src = &src[32..];
i += 32;
}
let i = i as usize;
let _ = hex_encode_sse41(src, &mut dst[i * 2..]);
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
}
// copied from https://github.com/Matherunner/bin2hex-sse/blob/master/base16_sse4.cpp
#[target_feature(enable = "sse4.1")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe fn hex_encode_sse41<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
let ascii_zero = _mm_set1_epi8(b'0' as i8);
let nines = _mm_set1_epi8(9);
let ascii_a = _mm_set1_epi8((b'a' - 9 - 1) as i8);
let and4bits = _mm_set1_epi8(0xf);
let mut i = 0_isize;
while src.len() >= 16 {
let invec = _mm_loadu_si128(src.as_ptr() as *const _);
let masked1 = _mm_and_si128(invec, and4bits);
let masked2 = _mm_and_si128(_mm_srli_epi64(invec, 4), and4bits);
// return 0xff corresponding to the elements > 9, or 0x00 otherwise
let cmpmask1 = _mm_cmpgt_epi8(masked1, nines);
let cmpmask2 = _mm_cmpgt_epi8(masked2, nines);
// add '0' or the offset depending on the masks
let masked1 = _mm_add_epi8(masked1, _mm_blendv_epi8(ascii_zero, ascii_a, cmpmask1));
let masked2 = _mm_add_epi8(masked2, _mm_blendv_epi8(ascii_zero, ascii_a, cmpmask2));
// interleave masked1 and masked2 bytes
let res1 = _mm_unpacklo_epi8(masked2, masked1);
let res2 = _mm_unpackhi_epi8(masked2, masked1);
_mm_storeu_si128(dst.as_mut_ptr().offset(i * 2) as *mut _, res1);
_mm_storeu_si128(dst.as_mut_ptr().offset(i * 2 + 16) as *mut _, res2);
src = &src[16..];
i += 16;
}
let i = i as usize;
let _ = hex_encode_fallback(src, &mut dst[i * 2..]);
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
}
#[cfg(target_arch = "wasm32")]
#[target_feature(enable = "simd128")]
unsafe fn hex_encode_simd128<'a>(mut src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
use core_arch::arch::wasm32::*;
let ascii_zero = i8x16_splat(b'0' as i8);
let nines = i8x16_splat(9);
let ascii_a = i8x16_splat((b'a' - 9 - 1) as i8);
let and4bits = i8x16_splat(0xf);
let mut i = 0_isize;
while src.len() >= 16 {
let invec = v128_load(src.as_ptr() as *const _);
let masked1 = v128_and(invec, and4bits);
let masked2 = v128_and(i8x16_shr_u(invec, 4), and4bits);
// return 0xff corresponding to the elements > 9, or 0x00 otherwise
let cmpmask1 = i8x16_gt_u(masked1, nines);
let cmpmask2 = i8x16_gt_u(masked2, nines);
// add '0' or the offset depending on the masks
let masked1 = i8x16_add(masked1, v128_bitselect(ascii_a, ascii_zero, cmpmask1));
let masked2 = i8x16_add(masked2, v128_bitselect(ascii_a, ascii_zero, cmpmask2));
// Next we need to shuffle around masked{1,2} to get back to the
// original source text order. The first element (res1) we'll store uses
// all the low bytes from the 2 masks and the second element (res2) uses
// all the upper bytes.
let res1 = v8x16_shuffle::<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23>(
masked2, masked1,
);
let res2 = v8x16_shuffle::<8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31>(
masked2, masked1,
);
v128_store(dst.as_mut_ptr().offset(i * 2) as *mut _, res1);
v128_store(dst.as_mut_ptr().offset(i * 2 + 16) as *mut _, res2);
src = &src[16..];
i += 16;
}
let i = i as usize;
let _ = hex_encode_fallback(src, &mut dst[i * 2..]);
Ok(str::from_utf8_unchecked(&dst[..src.len() * 2 + i * 2]))
}
fn hex_encode_fallback<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, usize> {
fn hex(byte: u8) -> u8 {
static TABLE: &[u8] = b"0123456789abcdef";
TABLE[byte as usize]
}
for (byte, slots) in src.iter().zip(dst.chunks_mut(2)) {
slots[0] = hex((*byte >> 4) & 0xf);
slots[1] = hex(*byte & 0xf);
}
unsafe { Ok(str::from_utf8_unchecked(&dst[..src.len() * 2])) }
}
// Run these with `cargo +nightly test --example hex -p stdarch`
#[cfg(test)]
mod tests {
use std::iter;
use super::*;
fn test(input: &[u8], output: &str) {
let tmp = || vec![0; input.len() * 2];
assert_eq!(hex_encode_fallback(input, &mut tmp()).unwrap(), output);
assert_eq!(hex_encode(input, &mut tmp()).unwrap(), output);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe {
if self::is_x86_feature_detected!("avx2") {
assert_eq!(hex_encode_avx2(input, &mut tmp()).unwrap(), output);
}
if self::is_x86_feature_detected!("sse4.1") {
assert_eq!(hex_encode_sse41(input, &mut tmp()).unwrap(), output);
}
}
}
#[test]
fn empty() {
test(b"", "");
}
#[test]
fn big() {
test(
&[0; 1024],
&iter::repeat('0').take(2048).collect::<String>(),
);
}
#[test]
fn odd() {
test(
&[0; 313],
&iter::repeat('0').take(313 * 2).collect::<String>(),
);
}
#[test]
fn avx_works() {
let mut input = [0; 33];
input[4] = 3;
input[16] = 3;
input[17] = 0x30;
input[21] = 1;
input[31] = 0x24;
test(
&input,
"\
0000000003000000\
0000000000000000\
0330000000010000\
0000000000000024\
00\
",
);
}
quickcheck::quickcheck! {
fn encode_equals_fallback(input: Vec<u8>) -> bool {
let mut space1 = vec![0; input.len() * 2];
let mut space2 = vec![0; input.len() * 2];
let a = hex_encode(&input, &mut space1).unwrap();
let b = hex_encode_fallback(&input, &mut space2).unwrap();
a == b
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn avx_equals_fallback(input: Vec<u8>) -> bool {
if !self::is_x86_feature_detected!("avx2") {
return true
}
let mut space1 = vec![0; input.len() * 2];
let mut space2 = vec![0; input.len() * 2];
let a = unsafe { hex_encode_avx2(&input, &mut space1).unwrap() };
let b = hex_encode_fallback(&input, &mut space2).unwrap();
a == b
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn sse41_equals_fallback(input: Vec<u8>) -> bool {
if !self::is_x86_feature_detected!("avx2") {
return true
}
let mut space1 = vec![0; input.len() * 2];
let mut space2 = vec![0; input.len() * 2];
let a = unsafe { hex_encode_sse41(&input, &mut space1).unwrap() };
let b = hex_encode_fallback(&input, &mut space2).unwrap();
a == b
}
}
}
// Run these with `cargo +nightly bench --example hex -p stdarch`
#[cfg(test)]
mod benches {
extern crate rand;
extern crate test;
use self::rand::Rng;
use super::*;
const SMALL_LEN: usize = 117;
const LARGE_LEN: usize = 1 * 1024 * 1024;
fn doit(
b: &mut test::Bencher,
len: usize,
f: for<'a> unsafe fn(&[u8], &'a mut [u8]) -> Result<&'a str, usize>,
) {
let mut rng = rand::thread_rng();
let input = std::iter::repeat(())
.map(|()| rng.gen::<u8>())
.take(len)
.collect::<Vec<_>>();
let mut dst = vec![0; input.len() * 2];
b.bytes = len as u64;
b.iter(|| unsafe {
f(&input, &mut dst).unwrap();
dst[0]
});
}
#[bench]
fn small_default(b: &mut test::Bencher) {
doit(b, SMALL_LEN, hex_encode);
}
#[bench]
fn small_fallback(b: &mut test::Bencher) {
doit(b, SMALL_LEN, hex_encode_fallback);
}
#[bench]
fn large_default(b: &mut test::Bencher) {
doit(b, LARGE_LEN, hex_encode);
}
#[bench]
fn large_fallback(b: &mut test::Bencher) {
doit(b, LARGE_LEN, hex_encode_fallback);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod x86 {
use super::*;
#[bench]
fn small_avx2(b: &mut test::Bencher) {
if self::is_x86_feature_detected!("avx2") {
doit(b, SMALL_LEN, hex_encode_avx2);
}
}
#[bench]
fn small_sse41(b: &mut test::Bencher) {
if self::is_x86_feature_detected!("sse4.1") {
doit(b, SMALL_LEN, hex_encode_sse41);
}
}
#[bench]
fn large_avx2(b: &mut test::Bencher) {
if self::is_x86_feature_detected!("avx2") {
doit(b, LARGE_LEN, hex_encode_avx2);
}
}
#[bench]
fn large_sse41(b: &mut test::Bencher) {
if self::is_x86_feature_detected!("sse4.1") {
doit(b, LARGE_LEN, hex_encode_sse41);
}
}
}
}