Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9d73c69

Browse files
committed
fix simd_bitmask return type for non-power-of-two inputs, and add tests
1 parent004f5b8 commit9d73c69

File tree

3 files changed

+132
-20
lines changed

3 files changed

+132
-20
lines changed

‎compiler/rustc_codegen_llvm/src/intrinsic.rs‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,8 +1119,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
11191119
if name == sym::simd_select_bitmask{
11201120
let(len, _) =require_simd!(arg_tys[1],SimdArgument);
11211121

1122-
let expected_int_bits =(len.max(8) -1).next_power_of_two();
1123-
let expected_bytes = len /8 +((len %8 >0)asu64);
1122+
let expected_int_bits = len.max(8).next_power_of_two();
1123+
let expected_bytes = len.div_ceil(8);
11241124

11251125
let mask_ty = arg_tys[0];
11261126
let mask =match mask_ty.kind(){
@@ -1377,17 +1377,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
13771377
}
13781378

13791379
if name == sym::simd_bitmask{
1380-
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
1381-
// vector mask and returns the most significant bit (MSB) of each lane in the form
1382-
// of either:
1380+
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a vector mask and
1381+
// returns one bit for each lane (which must all be `0` or `!0`) in the form of either:
13831382
// * an unsigned integer
13841383
// * an array of `u8`
13851384
// If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
13861385
//
13871386
// The bit order of the result depends on the byte endianness, LSB-first for little
13881387
// endian and MSB-first for big endian.
1389-
let expected_int_bits = in_len.max(8);
1390-
let expected_bytes =expected_int_bits /8 +((expected_int_bits %8 >0)asu64);
1388+
let expected_int_bits = in_len.max(8).next_power_of_two();
1389+
let expected_bytes =in_len.div_ceil(8);
13911390

13921391
// Integer vector <i{in_bitwidth} x in_len>:
13931392
let(i_xn, in_elem_bitwidth) =match in_elem.kind(){
@@ -1407,7 +1406,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
14071406
}),
14081407
};
14091408

1410-
// Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
1409+
// LLVM doesn't always know the inputs are `0` or `!0`, so we shift here so it optimizes to
1410+
// `pmovmskb` and similar on x86.
14111411
let shift_indices =
14121412
vec![
14131413
bx.cx.const_int(bx.type_ix(in_elem_bitwidth),(in_elem_bitwidth -1)as _);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//@run-pass
2+
// SEGFAULTS on LLVM 17. This hsould be merged into `simd-bitmask` once we require LLVM 18.
3+
//@ min-llvm-version: 18
4+
#![feature(repr_simd, intrinsics)]
5+
6+
extern"rust-intrinsic"{
7+
fnsimd_bitmask<T,U>(v:T) ->U;
8+
fnsimd_select_bitmask<T,U>(m:T,a:U,b:U) ->U;
9+
}
10+
11+
fnmain(){
12+
// Non-power-of-2 multi-byte mask.
13+
#[repr(simd, packed)]
14+
#[allow(non_camel_case_types)]
15+
#[derive(Copy,Clone,Debug,PartialEq)]
16+
structi32x10([i32;10]);
17+
impli32x10{
18+
fnsplat(x:i32) ->Self{
19+
Self([x;10])
20+
}
21+
}
22+
unsafe{
23+
let mask =i32x10([!0, !0,0, !0,0,0, !0,0, !0,0]);
24+
let mask_bits =ifcfg!(target_endian ="little"){0b0101001011}else{0b1101001010};
25+
let mask_bytes =
26+
ifcfg!(target_endian ="little"){[0b01001011,0b01]}else{[0b11,0b01001010]};
27+
28+
let bitmask1:u16 =simd_bitmask(mask);
29+
let bitmask2:[u8;2] =simd_bitmask(mask);
30+
assert_eq!(bitmask1, mask_bits);
31+
assert_eq!(bitmask2, mask_bytes);
32+
33+
let selected1 =simd_select_bitmask::<u16,_>(
34+
mask_bits,
35+
i32x10::splat(!0),// yes
36+
i32x10::splat(0),// no
37+
);
38+
let selected2 =simd_select_bitmask::<[u8;2],_>(
39+
mask_bytes,
40+
i32x10::splat(!0),// yes
41+
i32x10::splat(0),// no
42+
);
43+
assert_eq!(selected1, mask);
44+
assert_eq!(selected2, mask);
45+
}
46+
47+
// Test for a mask where the next multiple of 8 is not a power of two.
48+
/* FIXME: test is disabled because it segfaults on LLVM 17.
49+
Enable once we require LLVM 18.
50+
#[repr(simd, packed)]
51+
#[allow(non_camel_case_types)]
52+
#[derive(Copy, Clone, Debug, PartialEq)]
53+
struct i32x20([i32; 20]);
54+
impl i32x20 {
55+
fn splat(x: i32) -> Self {
56+
Self([x; 20])
57+
}
58+
}
59+
unsafe {
60+
let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]);
61+
let mask_bits = if cfg!(target_endian = "little") {
62+
0b11111110000101001011
63+
} else {
64+
0b11010010100001111111
65+
};
66+
let mask_bytes = if cfg!(target_endian = "little") {
67+
[0b01001011, 0b11100001, 0b1111]
68+
} else {
69+
[0b1101, 0b00101000, 0b01111111]
70+
};
71+
72+
let bitmask1: u32 = simd_bitmask(mask);
73+
let bitmask2: [u8; 3] = simd_bitmask(mask);
74+
assert_eq!(bitmask1, mask_bits);
75+
assert_eq!(bitmask2, mask_bytes);
76+
77+
let selected1 = simd_select_bitmask::<u32, _>(
78+
mask_bits,
79+
i32x20::splat(!0), // yes
80+
i32x20::splat(0), // no
81+
);
82+
let selected2 = simd_select_bitmask::<[u8; 3], _>(
83+
mask_bytes,
84+
i32x20::splat(!0), // yes
85+
i32x20::splat(0), // no
86+
);
87+
assert_eq!(selected1, mask);
88+
assert_eq!(selected2, mask);
89+
}
90+
*/
91+
}

‎tests/ui/simd/simd-bitmask.rs‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@run-pass
2-
//@ignore-endian-big behavior of simd_select_bitmask is endian-specific
32
#![feature(repr_simd, intrinsics)]
43

54
extern"rust-intrinsic"{
@@ -17,36 +16,58 @@ fn main() {
1716
let i:u8 =simd_bitmask(v);
1817
let a:[u8;1] =simd_bitmask(v);
1918

20-
assert_eq!(i,0b0101);
21-
assert_eq!(a,[0b0101]);
19+
ifcfg!(target_endian ="little"){
20+
assert_eq!(i,0b0101);
21+
assert_eq!(a,[0b0101]);
22+
}else{
23+
assert_eq!(i,0b1010);
24+
assert_eq!(a,[0b1010]);
25+
}
2226

2327
let v =Simd::<i8,16>([0,0, -1, -1,0,0,0,0,0,0,0,0, -1,0, -1,0]);
2428
let i:u16 =simd_bitmask(v);
2529
let a:[u8;2] =simd_bitmask(v);
2630

27-
assert_eq!(i,0b0101000000001100);
28-
assert_eq!(a,[0b1100,0b01010000]);
31+
ifcfg!(target_endian ="little"){
32+
assert_eq!(i,0b0101000000001100);
33+
assert_eq!(a,[0b00001100,0b01010000]);
34+
}else{
35+
assert_eq!(i,0b0011000000001010);
36+
assert_eq!(a,[0b00110000,0b00001010]);
37+
}
2938
}
3039

3140
unsafe{
32-
let a =Simd::<i32,8>([0,1,2,3,4,5,6,7]);
33-
let b =Simd::<i32,8>([8,9,10,11,12,13,14,15]);
34-
let e =[0,9,2,11,12,13,14,15];
41+
let a =Simd::<i32,4>([0,1,2,3]);
42+
let b =Simd::<i32,4>([8,9,10,11]);
43+
let e =[0,9,2,11];
3544

36-
let r =simd_select_bitmask(0b0101u8, a, b);
45+
let mask =ifcfg!(target_endian ="little"){0b0101u8}else{0b1010u8};
46+
let r =simd_select_bitmask(mask, a, b);
3747
assert_eq!(r.0, e);
3848

39-
let r =simd_select_bitmask([0b0101u8], a, b);
49+
let mask =ifcfg!(target_endian ="little"){[0b0101u8]}else{[0b1010u8]};
50+
let r =simd_select_bitmask(mask, a, b);
4051
assert_eq!(r.0, e);
4152

4253
let a =Simd::<i32,16>([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
4354
let b =Simd::<i32,16>([16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]);
4455
let e =[16,17,2,3,20,21,22,23,24,25,26,27,12,29,14,31];
4556

46-
let r =simd_select_bitmask(0b0101000000001100u16, a, b);
57+
let mask =ifcfg!(target_endian ="little"){
58+
0b0101000000001100u16
59+
}else{
60+
0b0011000000001010u16
61+
};
62+
let r =simd_select_bitmask(mask, a, b);
4763
assert_eq!(r.0, e);
4864

49-
let r =simd_select_bitmask([0b1100u8,0b01010000u8], a, b);
65+
let mask =ifcfg!(target_endian ="little"){
66+
[0b00001100u8,0b01010000u8]
67+
}else{
68+
[0b00110000u8,0b00001010u8]
69+
};
70+
let r =simd_select_bitmask(mask, a, b);
5071
assert_eq!(r.0, e);
5172
}
5273
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp