Skip to content

Commit bb123dd

Browse files
authored
Verify intrinsics don't leak to i686 (rust-lang#305)
Some intrinsics take `i64` or `u64` arguments which typically means that they're using 64-bit registers and aren't actually available on x86. This commit adds a check to stdsimd-verify to assert this and moves around some intrinsics that I believe should only be available on x86_64. This commit was checked in many places against gcc/clang/MSVC using godbolt.org to ensure that we're agreeing with what other compilers are doing. Closes rust-lang#304
1 parent a381482 commit bb123dd

File tree

14 files changed

+449
-336
lines changed

14 files changed

+449
-336
lines changed

coresimd/src/x86/i586/abm.rs

-28
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,6 @@ pub unsafe fn _lzcnt_u32(x: u32) -> u32 {
3030
x.leading_zeros()
3131
}
3232

33-
/// Counts the leading most significant zero bits.
34-
///
35-
/// When the operand is zero, it returns its size in bits.
36-
#[inline(always)]
37-
#[target_feature(enable = "lzcnt")]
38-
#[cfg_attr(test, assert_instr(lzcnt))]
39-
pub unsafe fn _lzcnt_u64(x: u64) -> u64 {
40-
x.leading_zeros() as u64
41-
}
42-
4333
/// Counts the bits that are set.
4434
#[inline(always)]
4535
#[target_feature(enable = "popcnt")]
@@ -48,14 +38,6 @@ pub unsafe fn _popcnt32(x: i32) -> i32 {
4838
x.count_ones() as i32
4939
}
5040

51-
/// Counts the bits that are set.
52-
#[inline(always)]
53-
#[target_feature(enable = "popcnt")]
54-
#[cfg_attr(test, assert_instr(popcnt))]
55-
pub unsafe fn _popcnt64(x: i64) -> i32 {
56-
x.count_ones() as i32
57-
}
58-
5941
#[cfg(test)]
6042
mod tests {
6143
use stdsimd_test::simd_test;
@@ -67,18 +49,8 @@ mod tests {
6749
assert_eq!(abm::_lzcnt_u32(0b0101_1010), 25);
6850
}
6951

70-
#[simd_test = "lzcnt"]
71-
unsafe fn _lzcnt_u64() {
72-
assert_eq!(abm::_lzcnt_u64(0b0101_1010), 57);
73-
}
74-
7552
#[simd_test = "popcnt"]
7653
unsafe fn _popcnt32() {
7754
assert_eq!(abm::_popcnt32(0b0101_1010), 4);
7855
}
79-
80-
#[simd_test = "popcnt"]
81-
unsafe fn _popcnt64() {
82-
assert_eq!(abm::_popcnt64(0b0101_1010), 4);
83-
}
8456
}

coresimd/src/x86/i586/avx.rs

-17
Original file line numberDiff line numberDiff line change
@@ -1245,15 +1245,6 @@ pub unsafe fn _mm256_insert_epi32(a: __m256i, i: i32, index: i32) -> __m256i {
12451245
mem::transmute(simd_insert(a.as_i32x8(), (index as u32) & 7, i))
12461246
}
12471247

1248-
/// Copy `a` to result, and insert the 64-bit integer `i` into result
1249-
/// at the location specified by `index`.
1250-
#[inline(always)]
1251-
#[target_feature(enable = "avx")]
1252-
// This intrinsic has no corresponding instruction.
1253-
pub unsafe fn _mm256_insert_epi64(a: __m256i, i: i64, index: i32) -> __m256i {
1254-
mem::transmute(simd_insert(a.as_i64x4(), (index as u32) & 3, i))
1255-
}
1256-
12571248
/// Load 256-bits (composed of 4 packed double-precision (64-bit)
12581249
/// floating-point elements) from memory into result.
12591250
/// `mem_addr` must be aligned on a 32-byte boundary or a
@@ -3307,14 +3298,6 @@ mod tests {
33073298
assert_eq_m256i(r, e);
33083299
}
33093300

3310-
#[simd_test = "avx"]
3311-
unsafe fn test_mm256_insert_epi64() {
3312-
let a = _mm256_setr_epi64x(1, 2, 3, 4);
3313-
let r = _mm256_insert_epi64(a, 0, 3);
3314-
let e = _mm256_setr_epi64x(1, 2, 3, 0);
3315-
assert_eq_m256i(r, e);
3316-
}
3317-
33183301
#[simd_test = "avx"]
33193302
unsafe fn test_mm256_load_pd() {
33203303
let a = _mm256_setr_pd(1., 2., 3., 4.);

coresimd/src/x86/i586/avx2.rs

-16
Original file line numberDiff line numberDiff line change
@@ -2887,15 +2887,6 @@ pub unsafe fn _mm256_extract_epi32(a: __m256i, imm8: i32) -> i32 {
28872887
simd_extract(a.as_i32x8(), imm8)
28882888
}
28892889

2890-
/// Extract a 64-bit integer from `a`, selected with `imm8`.
2891-
#[inline(always)]
2892-
#[target_feature(enable = "avx2")]
2893-
// This intrinsic has no corresponding instruction.
2894-
pub unsafe fn _mm256_extract_epi64(a: __m256i, imm8: i32) -> i64 {
2895-
let imm8 = (imm8 & 3) as u32;
2896-
simd_extract(a.as_i64x4(), imm8)
2897-
}
2898-
28992890
/// Returns the first element of the input vector of [4 x double].
29002891
#[inline(always)]
29012892
#[target_feature(enable = "avx2")]
@@ -5246,13 +5237,6 @@ mod tests {
52465237
assert_eq!(r2, 3);
52475238
}
52485239

5249-
#[simd_test = "avx2"]
5250-
unsafe fn test_mm256_extract_epi64() {
5251-
let a = _mm256_setr_epi64x(0, 1, 2, 3);
5252-
let r = _mm256_extract_epi64(a, 3);
5253-
assert_eq!(r, 3);
5254-
}
5255-
52565240
#[simd_test = "avx2"]
52575241
unsafe fn test_mm256_cvtsd_f64() {
52585242
let a = _mm256_setr_pd(1., 2., 3., 4.);

coresimd/src/x86/i586/bmi.rs

-143
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,6 @@ pub unsafe fn _bextr_u32(a: u32, start: u32, len: u32) -> u32 {
2121
_bextr2_u32(a, (start & 0xff_u32) | ((len & 0xff_u32) << 8_u32))
2222
}
2323

24-
/// Extracts bits in range [`start`, `start` + `length`) from `a` into
25-
/// the least significant bits of the result.
26-
#[inline(always)]
27-
#[target_feature(enable = "bmi")]
28-
#[cfg_attr(test, assert_instr(bextr))]
29-
#[cfg(not(target_arch = "x86"))]
30-
pub unsafe fn _bextr_u64(a: u64, start: u32, len: u32) -> u64 {
31-
_bextr2_u64(a, ((start & 0xff) | ((len & 0xff) << 8)) as u64)
32-
}
33-
3424
/// Extracts bits of `a` specified by `control` into
3525
/// the least significant bits of the result.
3626
///
@@ -43,19 +33,6 @@ pub unsafe fn _bextr2_u32(a: u32, control: u32) -> u32 {
4333
x86_bmi_bextr_32(a, control)
4434
}
4535

46-
/// Extracts bits of `a` specified by `control` into
47-
/// the least significant bits of the result.
48-
///
49-
/// Bits [7,0] of `control` specify the index to the first bit in the range to
50-
/// be extracted, and bits [15,8] specify the length of the range.
51-
#[inline(always)]
52-
#[target_feature(enable = "bmi")]
53-
#[cfg_attr(test, assert_instr(bextr))]
54-
#[cfg(not(target_arch = "x86"))]
55-
pub unsafe fn _bextr2_u64(a: u64, control: u64) -> u64 {
56-
x86_bmi_bextr_64(a, control)
57-
}
58-
5936
/// Bitwise logical `AND` of inverted `a` with `b`.
6037
#[inline(always)]
6138
#[target_feature(enable = "bmi")]
@@ -64,14 +41,6 @@ pub unsafe fn _andn_u32(a: u32, b: u32) -> u32 {
6441
!a & b
6542
}
6643

67-
/// Bitwise logical `AND` of inverted `a` with `b`.
68-
#[inline(always)]
69-
#[target_feature(enable = "bmi")]
70-
#[cfg_attr(test, assert_instr(andn))]
71-
pub unsafe fn _andn_u64(a: u64, b: u64) -> u64 {
72-
!a & b
73-
}
74-
7544
/// Extract lowest set isolated bit.
7645
#[inline(always)]
7746
#[target_feature(enable = "bmi")]
@@ -80,15 +49,6 @@ pub unsafe fn _blsi_u32(x: u32) -> u32 {
8049
x & x.wrapping_neg()
8150
}
8251

83-
/// Extract lowest set isolated bit.
84-
#[inline(always)]
85-
#[target_feature(enable = "bmi")]
86-
#[cfg_attr(test, assert_instr(blsi))]
87-
#[cfg(not(target_arch = "x86"))] // generates lots of instructions
88-
pub unsafe fn _blsi_u64(x: u64) -> u64 {
89-
x & x.wrapping_neg()
90-
}
91-
9252
/// Get mask up to lowest set bit.
9353
#[inline(always)]
9454
#[target_feature(enable = "bmi")]
@@ -97,15 +57,6 @@ pub unsafe fn _blsmsk_u32(x: u32) -> u32 {
9757
x ^ (x.wrapping_sub(1_u32))
9858
}
9959

100-
/// Get mask up to lowest set bit.
101-
#[inline(always)]
102-
#[target_feature(enable = "bmi")]
103-
#[cfg_attr(test, assert_instr(blsmsk))]
104-
#[cfg(not(target_arch = "x86"))] // generates lots of instructions
105-
pub unsafe fn _blsmsk_u64(x: u64) -> u64 {
106-
x ^ (x.wrapping_sub(1_u64))
107-
}
108-
10960
/// Resets the lowest set bit of `x`.
11061
///
11162
/// If `x` is sets CF.
@@ -116,17 +67,6 @@ pub unsafe fn _blsr_u32(x: u32) -> u32 {
11667
x & (x.wrapping_sub(1))
11768
}
11869

119-
/// Resets the lowest set bit of `x`.
120-
///
121-
/// If `x` is sets CF.
122-
#[inline(always)]
123-
#[target_feature(enable = "bmi")]
124-
#[cfg_attr(test, assert_instr(blsr))]
125-
#[cfg(not(target_arch = "x86"))] // generates lots of instructions
126-
pub unsafe fn _blsr_u64(x: u64) -> u64 {
127-
x & (x.wrapping_sub(1))
128-
}
129-
13070
/// Counts the number of trailing least significant zero bits.
13171
///
13272
/// When the source operand is 0, it returns its size in bits.
@@ -137,16 +77,6 @@ pub unsafe fn _tzcnt_u32(x: u32) -> u32 {
13777
x.trailing_zeros()
13878
}
13979

140-
/// Counts the number of trailing least significant zero bits.
141-
///
142-
/// When the source operand is 0, it returns its size in bits.
143-
#[inline(always)]
144-
#[target_feature(enable = "bmi")]
145-
#[cfg_attr(test, assert_instr(tzcnt))]
146-
pub unsafe fn _tzcnt_u64(x: u64) -> u64 {
147-
x.trailing_zeros() as u64
148-
}
149-
15080
/// Counts the number of trailing least significant zero bits.
15181
///
15282
/// When the source operand is 0, it returns its size in bits.
@@ -157,22 +87,9 @@ pub unsafe fn _mm_tzcnt_32(x: u32) -> i32 {
15787
x.trailing_zeros() as i32
15888
}
15989

160-
/// Counts the number of trailing least significant zero bits.
161-
///
162-
/// When the source operand is 0, it returns its size in bits.
163-
#[inline(always)]
164-
#[target_feature(enable = "bmi")]
165-
#[cfg_attr(test, assert_instr(tzcnt))]
166-
pub unsafe fn _mm_tzcnt_64(x: u64) -> i64 {
167-
x.trailing_zeros() as i64
168-
}
169-
170-
#[allow(dead_code)]
17190
extern "C" {
17291
#[link_name = "llvm.x86.bmi.bextr.32"]
17392
fn x86_bmi_bextr_32(x: u32, y: u32) -> u32;
174-
#[link_name = "llvm.x86.bmi.bextr.64"]
175-
fn x86_bmi_bextr_64(x: u64, y: u64) -> u64;
17693
}
17794

17895
#[cfg(test)]
@@ -187,13 +104,6 @@ mod tests {
187104
assert_eq!(r, 0b0000_0101u32);
188105
}
189106

190-
#[simd_test = "bmi"]
191-
#[cfg(not(target_arch = "x86"))]
192-
unsafe fn _bextr_u64() {
193-
let r = bmi::_bextr_u64(0b0101_0000u64, 4, 4);
194-
assert_eq!(r, 0b0000_0101u64);
195-
}
196-
197107
#[simd_test = "bmi"]
198108
unsafe fn _andn_u32() {
199109
assert_eq!(bmi::_andn_u32(0, 0), 0);
@@ -217,81 +127,28 @@ mod tests {
217127
assert_eq!(r, 0b0001_1101u32);
218128
}
219129

220-
#[simd_test = "bmi"]
221-
#[cfg(not(target_arch = "x86"))]
222-
unsafe fn _andn_u64() {
223-
assert_eq!(bmi::_andn_u64(0, 0), 0);
224-
assert_eq!(bmi::_andn_u64(0, 1), 1);
225-
assert_eq!(bmi::_andn_u64(1, 0), 0);
226-
assert_eq!(bmi::_andn_u64(1, 1), 0);
227-
228-
let r = bmi::_andn_u64(0b0000_0000u64, 0b0000_0000u64);
229-
assert_eq!(r, 0b0000_0000u64);
230-
231-
let r = bmi::_andn_u64(0b0000_0000u64, 0b1111_1111u64);
232-
assert_eq!(r, 0b1111_1111u64);
233-
234-
let r = bmi::_andn_u64(0b1111_1111u64, 0b0000_0000u64);
235-
assert_eq!(r, 0b0000_0000u64);
236-
237-
let r = bmi::_andn_u64(0b1111_1111u64, 0b1111_1111u64);
238-
assert_eq!(r, 0b0000_0000u64);
239-
240-
let r = bmi::_andn_u64(0b0100_0000u64, 0b0101_1101u64);
241-
assert_eq!(r, 0b0001_1101u64);
242-
}
243-
244130
#[simd_test = "bmi"]
245131
unsafe fn _blsi_u32() {
246132
assert_eq!(bmi::_blsi_u32(0b1101_0000u32), 0b0001_0000u32);
247133
}
248134

249-
#[simd_test = "bmi"]
250-
#[cfg(not(target_arch = "x86"))]
251-
unsafe fn _blsi_u64() {
252-
assert_eq!(bmi::_blsi_u64(0b1101_0000u64), 0b0001_0000u64);
253-
}
254-
255135
#[simd_test = "bmi"]
256136
unsafe fn _blsmsk_u32() {
257137
let r = bmi::_blsmsk_u32(0b0011_0000u32);
258138
assert_eq!(r, 0b0001_1111u32);
259139
}
260140

261-
#[simd_test = "bmi"]
262-
#[cfg(not(target_arch = "x86"))]
263-
unsafe fn _blsmsk_u64() {
264-
let r = bmi::_blsmsk_u64(0b0011_0000u64);
265-
assert_eq!(r, 0b0001_1111u64);
266-
}
267-
268141
#[simd_test = "bmi"]
269142
unsafe fn _blsr_u32() {
270143
// TODO: test the behavior when the input is 0
271144
let r = bmi::_blsr_u32(0b0011_0000u32);
272145
assert_eq!(r, 0b0010_0000u32);
273146
}
274147

275-
#[simd_test = "bmi"]
276-
#[cfg(not(target_arch = "x86"))]
277-
unsafe fn _blsr_u64() {
278-
// TODO: test the behavior when the input is 0
279-
let r = bmi::_blsr_u64(0b0011_0000u64);
280-
assert_eq!(r, 0b0010_0000u64);
281-
}
282-
283148
#[simd_test = "bmi"]
284149
unsafe fn _tzcnt_u32() {
285150
assert_eq!(bmi::_tzcnt_u32(0b0000_0001u32), 0u32);
286151
assert_eq!(bmi::_tzcnt_u32(0b0000_0000u32), 32u32);
287152
assert_eq!(bmi::_tzcnt_u32(0b1001_0000u32), 4u32);
288153
}
289-
290-
#[simd_test = "bmi"]
291-
#[cfg(not(target_arch = "x86"))]
292-
unsafe fn _tzcnt_u64() {
293-
assert_eq!(bmi::_tzcnt_u64(0b0000_0001u64), 0u64);
294-
assert_eq!(bmi::_tzcnt_u64(0b0000_0000u64), 64u64);
295-
assert_eq!(bmi::_tzcnt_u64(0b1001_0000u64), 4u64);
296-
}
297154
}

0 commit comments

Comments
 (0)