From f200fbca10b4cc066120c4d19b58d2f244c6e638 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 5 Sep 2022 15:37:56 +0000 Subject: [PATCH] Implement simd_bitmask --- ...table-simd-Disable-unsupported-tests.patch | 65 ++++++-------- src/intrinsics/simd.rs | 86 ++++++++++++++++++- 2 files changed, 111 insertions(+), 40 deletions(-) diff --git a/patches/0001-portable-simd-Disable-unsupported-tests.patch b/patches/0001-portable-simd-Disable-unsupported-tests.patch index a1824f86ce2..c75d5dda5ca 100644 --- a/patches/0001-portable-simd-Disable-unsupported-tests.patch +++ b/patches/0001-portable-simd-Disable-unsupported-tests.patch @@ -1,4 +1,4 @@ -From 82f597cf81b169b0e72a576ac8751f598c059c48 Mon Sep 17 00:00:00 2001 +From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Nov 2021 19:28:40 +0100 Subject: [PATCH] Disable unsupported tests @@ -6,10 +6,10 @@ Subject: [PATCH] Disable unsupported tests --- crates/core_simd/src/elements/int.rs | 8 ++++++++ crates/core_simd/src/elements/uint.rs | 4 ++++ - crates/core_simd/src/masks/full_masks.rs | 9 +++++++++ + crates/core_simd/src/masks/full_masks.rs | 6 ++++++ crates/core_simd/src/vector.rs | 2 ++ - crates/core_simd/tests/masks.rs | 2 ++ - 5 files changed, 25 insertions(+) + crates/core_simd/tests/masks.rs | 3 --- + 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/core_simd/src/elements/int.rs b/crates/core_simd/src/elements/int.rs index 9b8c37e..ea95f08 100644 @@ -116,10 +116,10 @@ index 21e7e76..0d6dee2 100644 #[inline] fn reduce_sum(self) -> Self::Scalar { diff --git a/crates/core_simd/src/masks/full_masks.rs b/crates/core_simd/src/masks/full_masks.rs -index adf0fcb..5b10292 100644 +index adf0fcb..e7e657e 100644 --- a/crates/core_simd/src/masks/full_masks.rs +++ b/crates/core_simd/src/masks/full_masks.rs -@@ -150,6 +150,7 @@ where +@@ -180,6 +180,7 @@ where super::Mask: ToBitMaskArray, [(); as ToBitMaskArray>::BYTES]: Sized, { @@ -127,33 +127,16 @@ index adf0fcb..5b10292 100644 assert_eq!( as ToBitMaskArray>::BYTES, N); // Safety: N is the correct bitmask size -@@ -170,6 +171,8 @@ where - - bitmask - } -+ */ -+ panic!(); - } - - #[cfg(feature = "generic_const_exprs")] -@@ -209,6 +212,7 @@ where - where - super::Mask: ToBitMask, - { -+ /* - // Safety: U is required to be the appropriate bitmask type - let bitmask: U = unsafe { intrinsics::simd_bitmask(self.0) }; - -@@ -218,6 +222,8 @@ where - } else { - bitmask +@@ -202,6 +203,8 @@ where + Self::splat(false).to_int(), + )) } + */ + panic!(); } #[inline] -@@ -225,6 +231,7 @@ where +@@ -225,6 +228,7 @@ where where super::Mask: ToBitMask, { @@ -161,7 +144,7 @@ index adf0fcb..5b10292 100644 // LLVM assumes bit order should match endianness let bitmask = if cfg!(target_endian = "big") { bitmask.reverse_bits(LANES) -@@ -240,6 +247,8 @@ where +@@ -240,6 +244,8 @@ where Self::splat(false).to_int(), )) } @@ -191,24 +174,30 @@ index e8e8f68..7173c24 100644 impl Copy for Simd diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs -index 673d0db..0d68b01 100644 +index 673d0db..3ebfcd1 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs -@@ -59,6 +59,7 @@ macro_rules! test_mask_api { - assert!(!v.all()); +@@ -78,7 +78,6 @@ macro_rules! test_mask_api { + let mask = core_simd::Mask::<$type, 16>::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1000001101001001); +- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); } -+ /* #[test] - fn roundtrip_int_conversion() { - let values = [true, false, false, true, false, false, true, false]; -@@ -99,6 +100,7 @@ macro_rules! test_mask_api { +@@ -91,13 +90,11 @@ macro_rules! test_mask_api { + let mask = core_simd::Mask::<$type, 4>::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1000); +- assert_eq!(core_simd::Mask::<$type, 4>::from_bitmask(bitmask), mask); + + let values = [true, false]; + let mask = core_simd::Mask::<$type, 2>::from_array(values); + let bitmask = mask.to_bitmask(); assert_eq!(bitmask, 0b01); - assert_eq!(core_simd::Mask::<$type, 2>::from_bitmask(bitmask), mask); +- assert_eq!(core_simd::Mask::<$type, 2>::from_bitmask(bitmask), mask); } -+ */ #[test] - fn cast() { -- 2.25.1 diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index a8aefcf30b5..4d77370dfc5 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_span::Symbol; +use rustc_target::abi::Endian; use super::*; use crate::prelude::*; @@ -162,6 +163,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } } else { + // FIXME remove this case intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap() }; @@ -650,10 +652,90 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } - // simd_saturating_* - // simd_bitmask + sym::simd_bitmask => { + intrinsic_args!(fx, args => (a); intrinsic); + + let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); + let lane_clif_ty = fx.clif_type(lane_ty).unwrap(); + + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a + // vector mask and returns the most significant bit (MSB) of each lane in the form + // of either: + // * an unsigned integer + // * an array of `u8` + // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. + // + // The bit order of the result depends on the byte endianness, LSB-first for little + // endian and MSB-first for big endian. + let expected_int_bits = lane_count.max(8); + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + + match lane_ty.kind() { + ty::Int(_) | ty::Uint(_) => {} + _ => { + fx.tcx.sess.span_fatal( + span, + &format!( + "invalid monomorphization of `simd_bitmask` intrinsic: \ + vector argument `{}`'s element type `{}`, expected integer element \ + type", + a.layout().ty, + lane_ty + ), + ); + } + } + + let res_type = + Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap(); + let mut res = fx.bcx.ins().iconst(res_type, 0); + + let lanes = match fx.tcx.sess.target.endian { + Endian::Big => Box::new(0..lane_count) as Box>, + Endian::Little => Box::new((0..lane_count).rev()) as Box>, + }; + for lane in lanes { + let a_lane = a.value_lane(fx, lane).load_scalar(fx); + + // extract sign bit of an int + let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_clif_ty.bits() - 1)); + + // shift sign bit into result + let a_lane_sign = clif_intcast(fx, a_lane_sign, res_type, false); + res = fx.bcx.ins().ishl_imm(res, 1); + res = fx.bcx.ins().bor(res, a_lane_sign); + } + + match ret.layout().ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {} + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => {} + _ => { + fx.tcx.sess.span_fatal( + span, + &format!( + "invalid monomorphization of `simd_bitmask` intrinsic: \ + cannot return `{}`, expected `u{}` or `[u8; {}]`", + ret.layout().ty, + expected_int_bits, + expected_bytes + ), + ); + } + } + + let res = CValue::by_val(res, ret.layout()); + ret.write_cvalue(fx, res); + } + + // simd_arith_offset + // simd_saturating_add + // simd_saturating_sub // simd_scatter // simd_gather + // simd_select_bitmask _ => { fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); }