Skip to content

Commit d464018

Browse files
authored
Add ADX-related intrinsics (#631)
Closes #322
1 parent 21c9eef commit d464018

File tree

8 files changed

+118
-3
lines changed

8 files changed

+118
-3
lines changed

coresimd/x86/adx.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#[cfg(test)]
2+
use stdsimd_test::assert_instr;
3+
4+
#[allow(improper_ctypes)]
5+
extern "unadjusted" {
6+
#[link_name = "llvm.x86.addcarry.u32"]
7+
fn llvm_addcarry_u32(a: u8, b: u32, c: u32) -> (u8, u32);
8+
#[link_name = "llvm.x86.subborrow.u32"]
9+
fn llvm_subborrow_u32(a: u8, b: u32, c: u32) -> (u8, u32);
10+
}
11+
12+
/// Add unsigned 32-bit integers a and b with unsigned 8-bit carry-in c_in
13+
/// (carry flag), and store the unsigned 32-bit result in out, and the carry-out
14+
/// is returned (carry or overflow flag).
15+
#[inline]
16+
#[cfg_attr(test, assert_instr(adc))]
17+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
18+
pub unsafe fn _addcarry_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
19+
let (a, b) = llvm_addcarry_u32(c_in, a, b);
20+
*out = b;
21+
a
22+
}
23+
24+
/// Add unsigned 32-bit integers a and b with unsigned 8-bit carry-in c_in
25+
/// (carry or overflow flag), and store the unsigned 32-bit result in out, and
26+
/// the carry-out is returned (carry or overflow flag).
27+
#[inline]
28+
#[target_feature(enable = "adx")]
29+
#[cfg_attr(test, assert_instr(adc))]
30+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
31+
#[cfg(not(stage0))]
32+
pub unsafe fn _addcarryx_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
33+
_addcarry_u32(c_in, a, b, out)
34+
}
35+
36+
/// Add unsigned 32-bit integers a and b with unsigned 8-bit carry-in c_in
37+
/// (carry or overflow flag), and store the unsigned 32-bit result in out, and
38+
/// the carry-out is returned (carry or overflow flag).
39+
#[inline]
40+
#[cfg_attr(test, assert_instr(sbb))]
41+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
42+
pub unsafe fn _subborrow_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
43+
let (a, b) = llvm_subborrow_u32(c_in, a, b);
44+
*out = b;
45+
a
46+
}

coresimd/x86/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,9 @@ pub use self::rdrand::*;
593593
mod sha;
594594
pub use self::sha::*;
595595

596+
mod adx;
597+
pub use self::adx::*;
598+
596599
#[cfg(test)]
597600
use stdsimd_test::assert_instr;
598601

coresimd/x86_64/adx.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#[cfg(test)]
2+
use stdsimd_test::assert_instr;
3+
4+
#[allow(improper_ctypes)]
5+
extern "unadjusted" {
6+
#[link_name = "llvm.x86.addcarry.u64"]
7+
fn llvm_addcarry_u64(a: u8, b: u64, c: u64) -> (u8, u64);
8+
#[link_name = "llvm.x86.subborrow.u64"]
9+
fn llvm_subborrow_u64(a: u8, b: u64, c: u64) -> (u8, u64);
10+
}
11+
12+
/// Add unsigned 64-bit integers a and b with unsigned 8-bit carry-in c_in
13+
/// (carry flag), and store the unsigned 64-bit result in out, and the carry-out
14+
/// is returned (carry or overflow flag).
15+
#[inline]
16+
#[cfg_attr(test, assert_instr(adc))]
17+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
18+
pub unsafe fn _addcarry_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 {
19+
let (a, b) = llvm_addcarry_u64(c_in, a, b);
20+
*out = b;
21+
a
22+
}
23+
24+
/// Add unsigned 64-bit integers a and b with unsigned 8-bit carry-in c_in
25+
/// (carry or overflow flag), and store the unsigned 64-bit result in out, and
26+
/// the carry-out is returned (carry or overflow flag).
27+
#[inline]
28+
#[target_feature(enable = "adx")]
29+
#[cfg_attr(test, assert_instr(adc))]
30+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
31+
#[cfg(not(stage0))]
32+
pub unsafe fn _addcarryx_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 {
33+
_addcarry_u64(c_in, a, b, out)
34+
}
35+
36+
/// Add unsigned 64-bit integers a and b with unsigned 8-bit carry-in c_in
37+
/// (carry or overflow flag), and store the unsigned 64-bit result in out, and
38+
/// the carry-out is returned (carry or overflow flag).
39+
#[inline]
40+
#[cfg_attr(test, assert_instr(sbb))]
41+
#[stable(feature = "simd_x86_adx", since = "1.33.0")]
42+
pub unsafe fn _subborrow_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 {
43+
let (a, b) = llvm_subborrow_u64(c_in, a, b);
44+
*out = b;
45+
a
46+
}

coresimd/x86_64/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,6 @@ pub use self::rdrand::*;
4141

4242
mod cmpxchg16b;
4343
pub use self::cmpxchg16b::*;
44+
45+
mod adx;
46+
pub use self::adx::*;

crates/coresimd/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
mips_target_feature,
3838
powerpc_target_feature,
3939
wasm_target_feature,
40-
abi_unadjusted
40+
abi_unadjusted,
41+
adx_target_feature
4142
)]
4243
// NB: When running nvptx/nvptx64 cross tests, enabling "integer_atomics" yields
4344
// a compile-time error: 'unknown feature `integer_atomics`'. This ought to be

crates/stdsimd-verify/tests/x86-intel.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,12 @@ fn matches(rust: &Function, intel: &Intrinsic) -> Result<(), String> {
240240
// ensuring that we've actually enabled the right instruction
241241
// set for this intrinsic.
242242
match rust.name {
243-
"_bswap" => {}
244-
"_bswap64" => {}
243+
"_bswap" | "_bswap64" => {}
244+
245+
// These don't actually have a target feature unlike their brethren with
246+
// the `x` inside the name which requires adx
247+
"_addcarry_u32" | "_addcarry_u64" | "_subborrow_u32" | "_subborrow_u64" => {}
248+
245249
_ => {
246250
if intel.cpuid.is_empty() {
247251
bail!("missing cpuid for {}", rust.name);

stdsimd/arch/detect/arch/x86.rs

+6
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ macro_rules! is_x86_feature_detected {
230230
cfg!(target_feature = "cmpxchg16b") || $crate::arch::detect::check_for(
231231
$crate::arch::detect::Feature::cmpxchg16b)
232232
};
233+
("adx") => {
234+
cfg!(target_feature = "adx") || $crate::arch::detect::check_for(
235+
$crate::arch::detect::Feature::adx)
236+
};
233237
($t:tt) => {
234238
compile_error!(concat!("unknown target feature: ", $t))
235239
};
@@ -322,4 +326,6 @@ pub enum Feature {
322326
xsavec,
323327
/// CMPXCH16B, a 16-byte compare-and-swap instruction
324328
cmpxchg16b,
329+
/// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
330+
adx,
325331
}

stdsimd/arch/detect/os/x86.rs

+6
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ fn detect_features() -> cache::Initializer {
124124
enable(proc_info_ecx, 1, Feature::pclmulqdq);
125125
enable(proc_info_ecx, 30, Feature::rdrand);
126126
enable(extended_features_ebx, 18, Feature::rdseed);
127+
enable(extended_features_ebx, 19, Feature::adx);
127128
enable(proc_info_edx, 4, Feature::tsc);
128129
enable(proc_info_edx, 23, Feature::mmx);
129130
enable(proc_info_edx, 24, Feature::fxsr);
@@ -290,6 +291,7 @@ mod tests {
290291
println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
291292
println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
292293
println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b"));
294+
println!("adx: {:?}", is_x86_feature_detected!("adx"));
293295
}
294296

295297
#[test]
@@ -350,5 +352,9 @@ mod tests {
350352
is_x86_feature_detected!("cmpxchg16b"),
351353
information.cmpxchg16b(),
352354
);
355+
assert_eq!(
356+
is_x86_feature_detected!("adx"),
357+
information.adx(),
358+
);
353359
}
354360
}

0 commit comments

Comments
 (0)