Skip to content

Commit

Permalink
Rollup merge of rust-lang#56789 - alexcrichton:simd_select_bitmask, r…
Browse files Browse the repository at this point in the history
…=rkruppe

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/stdarch#310
  • Loading branch information
kennytm committed Dec 14, 2018
2 parents 4a0ee22 + 5087aef commit 3397b79
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 5 deletions.
21 changes: 21 additions & 0 deletions src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
12 changes: 12 additions & 0 deletions src/test/codegen/simd-intrinsic-generic-select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@
#[derive(Copy, Clone, PartialEq, Debug)]
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
Expand All @@ -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)
}
30 changes: 30 additions & 0 deletions src/test/run-pass/simd/simd-intrinsic-generic-select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ struct i32x4(pub i32, pub i32, pub i32, pub i32);
#[derive(Copy, Clone, PartialEq, Debug)]
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);
Expand All @@ -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() {
Expand Down Expand Up @@ -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);
}
}
10 changes: 10 additions & 0 deletions src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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
}
}
26 changes: 22 additions & 4 deletions src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 3397b79

Please sign in to comment.