Skip to content

Commit 3981ca0

Browse files
committed
Allow simd_select_bitmask to take byte arrays
1 parent 7964942 commit 3981ca0

File tree

4 files changed

+70
-37
lines changed

4 files changed

+70
-37
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

+31-20
Original file line numberDiff line numberDiff line change
@@ -857,28 +857,39 @@ fn generic_simd_intrinsic(
857857
let arg_tys = sig.inputs();
858858

859859
if name == sym::simd_select_bitmask {
860-
let in_ty = arg_tys[0];
861-
let m_len = match in_ty.kind() {
862-
// Note that this `.unwrap()` crashes for isize/usize, that's sort
863-
// of intentional as there's not currently a use case for that.
864-
ty::Int(i) => i.bit_width().unwrap(),
865-
ty::Uint(i) => i.bit_width().unwrap(),
866-
_ => return_error!("`{}` is not an integral type", in_ty),
867-
};
868860
require_simd!(arg_tys[1], "argument");
869-
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
870-
require!(
871-
// Allow masks for vectors with fewer than 8 elements to be
872-
// represented with a u8 or i8.
873-
m_len == v_len || (m_len == 8 && v_len < 8),
874-
"mismatched lengths: mask length `{}` != other vector length `{}`",
875-
m_len,
876-
v_len
877-
);
861+
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
862+
863+
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
864+
let expected_bytes = len / 8 + ((len % 8 > 1) as u64);
865+
866+
let mask_ty = arg_tys[0];
867+
let mask = match mask_ty.kind() {
868+
ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
869+
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
870+
ty::Array(elem, len)
871+
if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
872+
&& len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
873+
== Some(expected_bytes) =>
874+
{
875+
let place = PlaceRef::alloca(bx, args[0].layout);
876+
args[0].val.store(bx, place);
877+
let int_ty = bx.type_ix(expected_bytes * 8);
878+
let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
879+
bx.load(int_ty, ptr, Align::ONE)
880+
}
881+
_ => return_error!(
882+
"invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
883+
mask_ty,
884+
expected_int_bits,
885+
expected_bytes
886+
),
887+
};
888+
878889
let i1 = bx.type_i1();
879-
let im = bx.type_ix(v_len);
880-
let i1xn = bx.type_vector(i1, v_len);
881-
let m_im = bx.trunc(args[0].immediate(), im);
890+
let im = bx.type_ix(len);
891+
let i1xn = bx.type_vector(i1, len);
892+
let m_im = bx.trunc(mask, im);
882893
let m_i1s = bx.bitcast(m_im, i1xn);
883894
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
884895
}

src/test/ui/simd/intrinsic/generic-select.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ struct b8x4(pub i8, pub i8, pub i8, pub i8);
2020

2121
#[repr(simd)]
2222
#[derive(Copy, Clone, PartialEq)]
23-
struct b8x8(pub i8, pub i8, pub i8, pub i8,
24-
pub i8, pub i8, pub i8, pub i8);
23+
struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8);
2524

2625
extern "platform-intrinsic" {
2726
fn simd_select<T, U>(x: T, a: U, b: U) -> U;
@@ -50,15 +49,15 @@ fn main() {
5049
//~^ ERROR found non-SIMD `u32`
5150

5251
simd_select_bitmask(0u16, x, x);
53-
//~^ ERROR mask length `16` != other vector length `4`
54-
//
52+
//~^ ERROR invalid bitmask `u16`, expected `u8` or `[u8; 1]`
53+
5554
simd_select_bitmask(0u8, 1u32, 2u32);
5655
//~^ ERROR found non-SIMD `u32`
5756

5857
simd_select_bitmask(0.0f32, x, x);
59-
//~^ ERROR `f32` is not an integral type
58+
//~^ ERROR invalid bitmask `f32`, expected `u8` or `[u8; 1]`
6059

6160
simd_select_bitmask("x", x, x);
62-
//~^ ERROR `&str` is not an integral type
61+
//~^ ERROR invalid bitmask `&str`, expected `u8` or `[u8; 1]`
6362
}
6463
}

src/test/ui/simd/intrinsic/generic-select.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
11
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
2-
--> $DIR/generic-select.rs:40:9
2+
--> $DIR/generic-select.rs:39:9
33
|
44
LL | simd_select(m8, x, x);
55
| ^^^^^^^^^^^^^^^^^^^^^
66

77
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_`
8-
--> $DIR/generic-select.rs:43:9
8+
--> $DIR/generic-select.rs:42:9
99
|
1010
LL | simd_select(x, x, x);
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_`
14-
--> $DIR/generic-select.rs:46:9
14+
--> $DIR/generic-select.rs:45:9
1515
|
1616
LL | simd_select(z, z, z);
1717
| ^^^^^^^^^^^^^^^^^^^^
1818

1919
error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32`
20-
--> $DIR/generic-select.rs:49:9
20+
--> $DIR/generic-select.rs:48:9
2121
|
2222
LL | simd_select(m4, 0u32, 1u32);
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
2424

25-
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
26-
--> $DIR/generic-select.rs:52:9
25+
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]`
26+
--> $DIR/generic-select.rs:51:9
2727
|
2828
LL | simd_select_bitmask(0u16, x, x);
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3030

3131
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
32-
--> $DIR/generic-select.rs:55:9
32+
--> $DIR/generic-select.rs:54:9
3333
|
3434
LL | simd_select_bitmask(0u8, 1u32, 2u32);
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3636

37-
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type
38-
--> $DIR/generic-select.rs:58:9
37+
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]`
38+
--> $DIR/generic-select.rs:57:9
3939
|
4040
LL | simd_select_bitmask(0.0f32, x, x);
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4242

43-
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type
44-
--> $DIR/generic-select.rs:61:9
43+
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]`
44+
--> $DIR/generic-select.rs:60:9
4545
|
4646
LL | simd_select_bitmask("x", x, x);
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/test/ui/simd/simd-bitmask.rs

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
extern "platform-intrinsic" {
55
fn simd_bitmask<T, U>(v: T) -> U;
6+
fn simd_select_bitmask<T, U>(m: T, a: U, b: U) -> U;
67
}
78

89
#[derive(Copy, Clone)]
@@ -25,4 +26,26 @@ fn main() {
2526
assert_eq!(i, 0b0101000000001100);
2627
assert_eq!(a, [0b1100, 0b01010000]);
2728
}
29+
30+
unsafe {
31+
let a = Simd::<i32, 8>([0, 1, 2, 3, 4, 5, 6, 7]);
32+
let b = Simd::<i32, 8>([8, 9, 10, 11, 12, 13, 14, 15]);
33+
let e = [0, 9, 2, 11, 12, 13, 14, 15];
34+
35+
let r = simd_select_bitmask(0b0101u8, a, b);
36+
assert_eq!(r.0, e);
37+
38+
let r = simd_select_bitmask([0b0101u8], a, b);
39+
assert_eq!(r.0, e);
40+
41+
let a = Simd::<i32, 16>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
42+
let b = Simd::<i32, 16>([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
43+
let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31];
44+
45+
let r = simd_select_bitmask(0b0101000000001100u16, a, b);
46+
assert_eq!(r.0, e);
47+
48+
let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b);
49+
assert_eq!(r.0, e);
50+
}
2851
}

0 commit comments

Comments
 (0)