about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-12-13 12:50:42 -0800
committerAlex Crichton <alex@alexcrichton.com>2018-12-13 14:05:12 -0800
commit5087aef79202e9f1411a0d0a0a74b0e63643a118 (patch)
treec698acf4b9af6e33b6165340583a4d1588ca7007
parentf4a421ee3cf1259f0750ac7fabd19da1d8551e4c (diff)
downloadrust-5087aef79202e9f1411a0d0a0a74b0e63643a118.tar.gz
rust-5087aef79202e9f1411a0d0a0a74b0e63643a118.zip
rustc: Add an unstable `simd_select_bitmask` intrinsic
This is going to be required for binding a number of AVX-512 intrinsics
in the `stdsimd` repository, and this intrinsic is the same as
`simd_select` except that it takes a bitmask as the first argument
instead of a SIMD vector. This bitmask is then transmuted into a `<NN x
i8>` argument, depending on how many bits it is.

cc rust-lang-nursery/stdsimd#310
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs21
-rw-r--r--src/librustc_typeck/check/intrinsic.rs3
-rw-r--r--src/test/codegen/simd-intrinsic-generic-select.rs12
-rw-r--r--src/test/run-pass/simd/simd-intrinsic-generic-select.rs30
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs10
-rw-r--r--src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr26
6 files changed, 97 insertions, 5 deletions
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 2b82ebe0bc2..8b26ada1576 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -1171,6 +1171,27 @@ fn generic_simd_intrinsic(
     );
     let arg_tys = sig.inputs();
 
+    if name == "simd_select_bitmask" {
+        let in_ty = arg_tys[0];
+        let m_len = match in_ty.sty {
+            // Note that this `.unwrap()` crashes for isize/usize, that's sort
+            // of intentional as there's not currently a use case for that.
+            ty::Int(i) => i.bit_width().unwrap(),
+            ty::Uint(i) => i.bit_width().unwrap(),
+            _ => return_error!("`{}` is not an integral type", in_ty),
+        };
+        require_simd!(arg_tys[1], "argument");
+        let v_len = arg_tys[1].simd_size(tcx);
+        require!(m_len == v_len,
+                 "mismatched lengths: mask length `{}` != other vector length `{}`",
+                 m_len, v_len
+        );
+        let i1 = bx.type_i1();
+        let i1xn = bx.type_vector(i1, m_len as u64);
+        let m_i1s = bx.bitcast(args[0].immediate(), i1xn);
+        return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
+    }
+
     // every intrinsic takes a SIMD vector as its first argument
     require_simd!(arg_tys[0], "input");
     let in_ty = arg_tys[0];
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 5c0eef5b1f3..a40e56d68ae 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -435,7 +435,8 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
         "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
         "simd_cast" => (2, vec![param(0)], param(1)),
-        "simd_select" => (2, vec![param(0), param(1), param(1)], param(1)),
+        "simd_select" |
+        "simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)),
         "simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
         "simd_reduce_add_ordered" | "simd_reduce_mul_ordered"
             => (2, vec![param(0), param(1)], param(1)),
diff --git a/src/test/codegen/simd-intrinsic-generic-select.rs b/src/test/codegen/simd-intrinsic-generic-select.rs
index 8a64d7437d8..24a4b2b1b05 100644
--- a/src/test/codegen/simd-intrinsic-generic-select.rs
+++ b/src/test/codegen/simd-intrinsic-generic-select.rs
@@ -21,10 +21,15 @@ pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
 
 #[repr(simd)]
 #[derive(Copy, Clone, PartialEq, Debug)]
+pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub struct b8x4(pub i8, pub i8, pub i8, pub i8);
 
 extern "platform-intrinsic" {
     fn simd_select<T, U>(x: T, a: U, b: U) -> U;
+    fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
 }
 
 // CHECK-LABEL: @select
@@ -33,3 +38,10 @@ pub unsafe fn select(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
     // CHECK: select <4 x i1>
     simd_select(m, a, b)
 }
+
+// CHECK-LABEL: @select_bitmask
+#[no_mangle]
+pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 {
+    // CHECK: select <8 x i1>
+    simd_select_bitmask(m, a, b)
+}
diff --git a/src/test/run-pass/simd/simd-intrinsic-generic-select.rs b/src/test/run-pass/simd/simd-intrinsic-generic-select.rs
index 590a2990270..74b99ca4950 100644
--- a/src/test/run-pass/simd/simd-intrinsic-generic-select.rs
+++ b/src/test/run-pass/simd/simd-intrinsic-generic-select.rs
@@ -28,6 +28,10 @@ struct u32x4(pub u32, pub u32, pub u32, pub u32);
 
 #[repr(simd)]
 #[derive(Copy, Clone, PartialEq, Debug)]
+struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 struct f32x4(pub f32, pub f32, pub f32, pub f32);
 
 #[repr(simd)]
@@ -36,6 +40,7 @@ struct b8x4(pub i8, pub i8, pub i8, pub i8);
 
 extern "platform-intrinsic" {
     fn simd_select<T, U>(x: T, a: U, b: U) -> U;
+    fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
 }
 
 fn main() {
@@ -146,4 +151,29 @@ fn main() {
         let e = b8x4(t, f, t, t);
         assert_eq!(r, e);
     }
+
+    unsafe {
+        let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7);
+        let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15);
+
+        let r: u32x8 = simd_select_bitmask(0u8, a, b);
+        let e = b;
+        assert_eq!(r, e);
+
+        let r: u32x8 = simd_select_bitmask(0xffu8, a, b);
+        let e = a;
+        assert_eq!(r, e);
+
+        let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b);
+        let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15);
+        assert_eq!(r, e);
+
+        let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b);
+        let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7);
+        assert_eq!(r, e);
+
+        let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b);
+        let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
+        assert_eq!(r, e);
+    }
 }
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
index d74d6815d5f..2a2d35e7bd9 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -33,6 +33,7 @@ struct b8x8(pub i8, pub i8, pub i8, pub i8,
 
 extern "platform-intrinsic" {
     fn simd_select<T, U>(x: T, a: U, b: U) -> U;
+    fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U;
 }
 
 fn main() {
@@ -52,5 +53,14 @@ fn main() {
 
         simd_select(z, z, z);
         //~^ ERROR mask element type is `f32`, expected `i_`
+
+        simd_select_bitmask(0u8, x, x);
+        //~^ ERROR mask length `8` != other vector length `4`
+
+        simd_select_bitmask(0.0f32, x, x);
+        //~^ ERROR `f32` is not an integral type
+
+        simd_select_bitmask("x", x, x);
+        //~^ ERROR `&str` is not an integral type
     }
 }
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
index 61e42027039..584f3d53921 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
@@ -1,21 +1,39 @@
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
-  --> $DIR/simd-intrinsic-generic-select.rs:47:9
+  --> $DIR/simd-intrinsic-generic-select.rs:48:9
    |
 LL |         simd_select(m8, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_`
-  --> $DIR/simd-intrinsic-generic-select.rs:50:9
+  --> $DIR/simd-intrinsic-generic-select.rs:51:9
    |
 LL |         simd_select(x, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_`
-  --> $DIR/simd-intrinsic-generic-select.rs:53:9
+  --> $DIR/simd-intrinsic-generic-select.rs:54:9
    |
 LL |         simd_select(z, z, z);
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
+  --> $DIR/simd-intrinsic-generic-select.rs:57:9
+   |
+LL |         simd_select_bitmask(0u8, x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type
+  --> $DIR/simd-intrinsic-generic-select.rs:60:9
+   |
+LL |         simd_select_bitmask(0.0f32, x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type
+  --> $DIR/simd-intrinsic-generic-select.rs:63:9
+   |
+LL |         simd_select_bitmask("x", x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0511`.