Skip to content

Commit

Permalink
Implemented rdrand and rdseed intrinsics (rust-lang#326)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
newpavlov authored and alexcrichton committed Feb 27, 2018
1 parent d0a6c2c commit dacb3c2
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 0 deletions.
3 changes: 3 additions & 0 deletions coresimd/x86/i686/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
mod aes;
pub use self::aes::*;

mod rdrand;
pub use self::rdrand::*;

mod mmx;
pub use self::mmx::*;

Expand Down
57 changes: 57 additions & 0 deletions coresimd/x86/i686/rdrand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! RDRAND and RDSEED instructions for returning random numbers from an Intel
//! on-chip hardware random number generator which has been seeded by an on-chip
//! entropy source.
extern "platform-intrinsic" {
fn x86_rdrand16_step() -> (u16, i32);
fn x86_rdrand32_step() -> (u32, i32);
fn x86_rdseed16_step() -> (u16, i32);
fn x86_rdseed32_step() -> (u32, i32);
}

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Read a hardware generated 16-bit random value and store the result in val.
/// Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdrand")]
#[cfg_attr(test, assert_instr(rdrand))]
pub unsafe fn _rdrand16_step(val: &mut u16) -> i32 {
let (v, flag) = x86_rdrand16_step();
*val = v;
flag
}

/// Read a hardware generated 32-bit random value and store the result in val.
/// Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdrand")]
#[cfg_attr(test, assert_instr(rdrand))]
pub unsafe fn _rdrand32_step(val: &mut u32) -> i32 {
let (v, flag) = x86_rdrand32_step();
*val = v;
flag
}

/// Read a 16-bit NIST SP800-90B and SP800-90C compliant random value and store
/// in val. Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdseed")]
#[cfg_attr(test, assert_instr(rdseed))]
pub unsafe fn _rdseed16_step(val: &mut u16) -> i32 {
let (v, flag) = x86_rdseed16_step();
*val = v;
flag
}

/// Read a 32-bit NIST SP800-90B and SP800-90C compliant random value and store
/// in val. Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdseed")]
#[cfg_attr(test, assert_instr(rdseed))]
pub unsafe fn _rdseed32_step(val: &mut u32) -> i32 {
let (v, flag) = x86_rdseed32_step();
*val = v;
flag
}
3 changes: 3 additions & 0 deletions coresimd/x86/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ pub use self::avx2::*;

mod bswap;
pub use self::bswap::*;

mod rdrand;
pub use self::rdrand::*;
33 changes: 33 additions & 0 deletions coresimd/x86/x86_64/rdrand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! RDRAND and RDSEED instructions for returning random numbers from an Intel
//! on-chip hardware random number generator which has been seeded by an on-chip
//! entropy source.
extern "platform-intrinsic" {
fn x86_rdrand64_step() -> (u64, i32);
fn x86_rdseed64_step() -> (u64, i32);
}

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Read a hardware generated 64-bit random value and store the result in val.
/// Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdrand")]
#[cfg_attr(test, assert_instr(rdrand))]
pub unsafe fn _rdrand64_step(val: &mut u64) -> i32 {
let (v, flag) = x86_rdrand64_step();
*val = v;
flag
}

/// Read a 64-bit NIST SP800-90B and SP800-90C compliant random value and store
/// in val. Return 1 if a random value was generated, and 0 otherwise.
#[inline]
#[target_feature(enable = "rdseed")]
#[cfg_attr(test, assert_instr(rdseed))]
pub unsafe fn _rdseed64_step(val: &mut u64) -> i32 {
let (v, flag) = x86_rdseed64_step();
*val = v;
flag
}
1 change: 1 addition & 0 deletions crates/stdsimd-verify/tests/x86-intel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ fn equate(t: &Type,
(&Type::Ptr(&Type::PrimSigned(32)), "int*") => {}
(&Type::Ptr(&Type::PrimSigned(64)), "__int64*") => {}
(&Type::Ptr(&Type::PrimSigned(8)), "char*") => {}
(&Type::Ptr(&Type::PrimUnsigned(16)), "unsigned short*") => {}
(&Type::Ptr(&Type::PrimUnsigned(32)), "unsigned int*") => {}
(&Type::Ptr(&Type::PrimUnsigned(64)), "unsigned __int64*") => {}
(&Type::Ptr(&Type::PrimUnsigned(8)), "const void*") => {}
Expand Down
16 changes: 16 additions & 0 deletions stdsimd/arch/detect/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ macro_rules! is_target_feature_detected {
("pclmulqdq") => {
$crate::arch::detect::check_for(
$crate::arch::detect::Feature::pclmulqdq) };
("rdrand") => {
$crate::arch::detect::check_for(
$crate::arch::detect::Feature::rdrand) };
("rdseed") => {
$crate::arch::detect::check_for(
$crate::arch::detect::Feature::rdseed) };
("tsc") => {
$crate::arch::detect::check_for(
$crate::arch::detect::Feature::tsc) };
Expand Down Expand Up @@ -180,6 +186,10 @@ pub enum Feature {
aes,
/// CLMUL (Carry-less Multiplication)
pclmulqdq,
/// RDRAND
rdrand,
/// RDSEED
rdseed,
/// TSC (Time Stamp Counter)
tsc,
/// MMX
Expand Down Expand Up @@ -352,6 +362,8 @@ pub fn detect_features() -> cache::Initializer {
enable(proc_info_ecx, 23, Feature::popcnt);
enable(proc_info_ecx, 25, Feature::aes);
enable(proc_info_ecx, 1, Feature::pclmulqdq);
enable(proc_info_ecx, 30, Feature::rdrand);
enable(extended_features_ebx, 18, Feature::rdseed);
enable(proc_info_edx, 4, Feature::tsc);
enable(proc_info_edx, 23, Feature::mmx);
enable(proc_info_edx, 24, Feature::fxsr);
Expand Down Expand Up @@ -465,6 +477,8 @@ mod tests {
fn dump() {
println!("aes: {:?}", is_target_feature_detected!("aes"));
println!("pclmulqdq: {:?}", is_target_feature_detected!("pclmulqdq"));
println!("rdrand: {:?}", is_target_feature_detected!("rdrand"));
println!("rdseed: {:?}", is_target_feature_detected!("rdseed"));
println!("tsc: {:?}", is_target_feature_detected!("tsc"));
println!("sse: {:?}", is_target_feature_detected!("sse"));
println!("sse2: {:?}", is_target_feature_detected!("sse2"));
Expand Down Expand Up @@ -507,6 +521,8 @@ mod tests {
let information = cupid::master().unwrap();
assert_eq!(is_target_feature_detected!("aes"), information.aesni());
assert_eq!(is_target_feature_detected!("pclmulqdq"), information.pclmulqdq());
assert_eq!(is_target_feature_detected!("rdrand"), information.rdrand());
assert_eq!(is_target_feature_detected!("rdseed"), information.rdseed());
assert_eq!(is_target_feature_detected!("tsc"), information.tsc());
assert_eq!(is_target_feature_detected!("sse"), information.sse());
assert_eq!(is_target_feature_detected!("sse2"), information.sse2());
Expand Down

0 comments on commit dacb3c2

Please sign in to comment.