Skip to content

Commit dacb3c2

Browse files
newpavlovalexcrichton
authored andcommitted
Implemented rdrand and rdseed intrinsics (#326)
* implemented rdrand and rdseed intrinsics * added "unsigned short*" case * moved rdrand from i686 to x86_64 * 64 bit rdrand functions in x86_64, 16 and 32 in i686
1 parent d0a6c2c commit dacb3c2

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

coresimd/x86/i686/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
mod aes;
44
pub use self::aes::*;
55

6+
mod rdrand;
7+
pub use self::rdrand::*;
8+
69
mod mmx;
710
pub use self::mmx::*;
811

coresimd/x86/i686/rdrand.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! RDRAND and RDSEED instructions for returning random numbers from an Intel
2+
//! on-chip hardware random number generator which has been seeded by an on-chip
3+
//! entropy source.
4+
5+
extern "platform-intrinsic" {
6+
fn x86_rdrand16_step() -> (u16, i32);
7+
fn x86_rdrand32_step() -> (u32, i32);
8+
fn x86_rdseed16_step() -> (u16, i32);
9+
fn x86_rdseed32_step() -> (u32, i32);
10+
}
11+
12+
#[cfg(test)]
13+
use stdsimd_test::assert_instr;
14+
15+
/// Read a hardware generated 16-bit random value and store the result in val.
16+
/// Return 1 if a random value was generated, and 0 otherwise.
17+
#[inline]
18+
#[target_feature(enable = "rdrand")]
19+
#[cfg_attr(test, assert_instr(rdrand))]
20+
pub unsafe fn _rdrand16_step(val: &mut u16) -> i32 {
21+
let (v, flag) = x86_rdrand16_step();
22+
*val = v;
23+
flag
24+
}
25+
26+
/// Read a hardware generated 32-bit random value and store the result in val.
27+
/// Return 1 if a random value was generated, and 0 otherwise.
28+
#[inline]
29+
#[target_feature(enable = "rdrand")]
30+
#[cfg_attr(test, assert_instr(rdrand))]
31+
pub unsafe fn _rdrand32_step(val: &mut u32) -> i32 {
32+
let (v, flag) = x86_rdrand32_step();
33+
*val = v;
34+
flag
35+
}
36+
37+
/// Read a 16-bit NIST SP800-90B and SP800-90C compliant random value and store
38+
/// in val. Return 1 if a random value was generated, and 0 otherwise.
39+
#[inline]
40+
#[target_feature(enable = "rdseed")]
41+
#[cfg_attr(test, assert_instr(rdseed))]
42+
pub unsafe fn _rdseed16_step(val: &mut u16) -> i32 {
43+
let (v, flag) = x86_rdseed16_step();
44+
*val = v;
45+
flag
46+
}
47+
48+
/// Read a 32-bit NIST SP800-90B and SP800-90C compliant random value and store
49+
/// in val. Return 1 if a random value was generated, and 0 otherwise.
50+
#[inline]
51+
#[target_feature(enable = "rdseed")]
52+
#[cfg_attr(test, assert_instr(rdseed))]
53+
pub unsafe fn _rdseed32_step(val: &mut u32) -> i32 {
54+
let (v, flag) = x86_rdseed32_step();
55+
*val = v;
56+
flag
57+
}

coresimd/x86/x86_64/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ pub use self::avx2::*;
3737

3838
mod bswap;
3939
pub use self::bswap::*;
40+
41+
mod rdrand;
42+
pub use self::rdrand::*;

coresimd/x86/x86_64/rdrand.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! RDRAND and RDSEED instructions for returning random numbers from an Intel
2+
//! on-chip hardware random number generator which has been seeded by an on-chip
3+
//! entropy source.
4+
5+
extern "platform-intrinsic" {
6+
fn x86_rdrand64_step() -> (u64, i32);
7+
fn x86_rdseed64_step() -> (u64, i32);
8+
}
9+
10+
#[cfg(test)]
11+
use stdsimd_test::assert_instr;
12+
13+
/// Read a hardware generated 64-bit random value and store the result in val.
14+
/// Return 1 if a random value was generated, and 0 otherwise.
15+
#[inline]
16+
#[target_feature(enable = "rdrand")]
17+
#[cfg_attr(test, assert_instr(rdrand))]
18+
pub unsafe fn _rdrand64_step(val: &mut u64) -> i32 {
19+
let (v, flag) = x86_rdrand64_step();
20+
*val = v;
21+
flag
22+
}
23+
24+
/// Read a 64-bit NIST SP800-90B and SP800-90C compliant random value and store
25+
/// in val. Return 1 if a random value was generated, and 0 otherwise.
26+
#[inline]
27+
#[target_feature(enable = "rdseed")]
28+
#[cfg_attr(test, assert_instr(rdseed))]
29+
pub unsafe fn _rdseed64_step(val: &mut u64) -> i32 {
30+
let (v, flag) = x86_rdseed64_step();
31+
*val = v;
32+
flag
33+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ fn equate(t: &Type,
395395
(&Type::Ptr(&Type::PrimSigned(32)), "int*") => {}
396396
(&Type::Ptr(&Type::PrimSigned(64)), "__int64*") => {}
397397
(&Type::Ptr(&Type::PrimSigned(8)), "char*") => {}
398+
(&Type::Ptr(&Type::PrimUnsigned(16)), "unsigned short*") => {}
398399
(&Type::Ptr(&Type::PrimUnsigned(32)), "unsigned int*") => {}
399400
(&Type::Ptr(&Type::PrimUnsigned(64)), "unsigned __int64*") => {}
400401
(&Type::Ptr(&Type::PrimUnsigned(8)), "const void*") => {}

stdsimd/arch/detect/x86.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ macro_rules! is_target_feature_detected {
3434
("pclmulqdq") => {
3535
$crate::arch::detect::check_for(
3636
$crate::arch::detect::Feature::pclmulqdq) };
37+
("rdrand") => {
38+
$crate::arch::detect::check_for(
39+
$crate::arch::detect::Feature::rdrand) };
40+
("rdseed") => {
41+
$crate::arch::detect::check_for(
42+
$crate::arch::detect::Feature::rdseed) };
3743
("tsc") => {
3844
$crate::arch::detect::check_for(
3945
$crate::arch::detect::Feature::tsc) };
@@ -180,6 +186,10 @@ pub enum Feature {
180186
aes,
181187
/// CLMUL (Carry-less Multiplication)
182188
pclmulqdq,
189+
/// RDRAND
190+
rdrand,
191+
/// RDSEED
192+
rdseed,
183193
/// TSC (Time Stamp Counter)
184194
tsc,
185195
/// MMX
@@ -352,6 +362,8 @@ pub fn detect_features() -> cache::Initializer {
352362
enable(proc_info_ecx, 23, Feature::popcnt);
353363
enable(proc_info_ecx, 25, Feature::aes);
354364
enable(proc_info_ecx, 1, Feature::pclmulqdq);
365+
enable(proc_info_ecx, 30, Feature::rdrand);
366+
enable(extended_features_ebx, 18, Feature::rdseed);
355367
enable(proc_info_edx, 4, Feature::tsc);
356368
enable(proc_info_edx, 23, Feature::mmx);
357369
enable(proc_info_edx, 24, Feature::fxsr);
@@ -465,6 +477,8 @@ mod tests {
465477
fn dump() {
466478
println!("aes: {:?}", is_target_feature_detected!("aes"));
467479
println!("pclmulqdq: {:?}", is_target_feature_detected!("pclmulqdq"));
480+
println!("rdrand: {:?}", is_target_feature_detected!("rdrand"));
481+
println!("rdseed: {:?}", is_target_feature_detected!("rdseed"));
468482
println!("tsc: {:?}", is_target_feature_detected!("tsc"));
469483
println!("sse: {:?}", is_target_feature_detected!("sse"));
470484
println!("sse2: {:?}", is_target_feature_detected!("sse2"));
@@ -507,6 +521,8 @@ mod tests {
507521
let information = cupid::master().unwrap();
508522
assert_eq!(is_target_feature_detected!("aes"), information.aesni());
509523
assert_eq!(is_target_feature_detected!("pclmulqdq"), information.pclmulqdq());
524+
assert_eq!(is_target_feature_detected!("rdrand"), information.rdrand());
525+
assert_eq!(is_target_feature_detected!("rdseed"), information.rdseed());
510526
assert_eq!(is_target_feature_detected!("tsc"), information.tsc());
511527
assert_eq!(is_target_feature_detected!("sse"), information.sse());
512528
assert_eq!(is_target_feature_detected!("sse2"), information.sse2());

0 commit comments

Comments
 (0)