#[cfg(all(
not(feature = "std"),
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
use spin::Once;
#[cfg(all(
feature = "std",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
use std::sync::OnceLock;
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;
#[cfg(all(
feature = "alloc",
not(feature = "std"),
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
use alloc::string::{String, ToString};
#[cfg(any(
test,
all(
feature = "std",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
)
))]
use std::string::{String, ToString};
#[cfg(all(
feature = "std",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
static ARCH_OPS_INSTANCE: OnceLock<ArchOpsInstance> = OnceLock::new();
#[cfg(all(
not(feature = "std"),
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
static ARCH_OPS_INSTANCE: Once<ArchOpsInstance> = Once::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)] pub enum PerformanceTier {
AArch64AesSha3,
AArch64Aes,
X86_64Avx512Vpclmulqdq,
X86_64Avx512Pclmulqdq,
X86_64SsePclmulqdq,
X86SsePclmulqdq,
SoftwareTable,
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)] pub struct ArchCapabilities {
pub has_aes: bool, pub has_crc: bool, pub has_sha3: bool,
pub has_sse41: bool,
pub has_sse42: bool, pub has_pclmulqdq: bool,
pub has_avx512vl: bool, pub has_vpclmulqdq: bool,
}
#[cfg(any(
test,
all(
feature = "alloc",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
)
))]
#[inline(always)]
fn tier_to_target_string(tier: PerformanceTier) -> String {
match tier {
PerformanceTier::AArch64AesSha3 => "aarch64-neon-pmull-sha3".to_string(),
PerformanceTier::AArch64Aes => "aarch64-neon-pmull".to_string(),
PerformanceTier::X86_64Avx512Vpclmulqdq => "x86_64-avx512-vpclmulqdq".to_string(),
PerformanceTier::X86_64Avx512Pclmulqdq => "x86_64-avx512-pclmulqdq".to_string(),
PerformanceTier::X86_64SsePclmulqdq => "x86_64-sse-pclmulqdq".to_string(),
PerformanceTier::X86SsePclmulqdq => "x86-sse-pclmulqdq".to_string(),
PerformanceTier::SoftwareTable => "software-fallback-tables".to_string(),
}
}
#[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
unsafe fn detect_arch_capabilities() -> ArchCapabilities {
#[cfg(target_arch = "aarch64")]
{
detect_aarch64_features()
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
detect_x86_features()
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")))]
{
ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
}
}
}
#[inline(always)]
#[cfg(all(target_arch = "aarch64", feature = "std"))]
unsafe fn detect_aarch64_features() -> ArchCapabilities {
use std::arch::is_aarch64_feature_detected;
let has_aes = is_aarch64_feature_detected!("aes");
let has_crc = is_aarch64_feature_detected!("crc");
let has_sha3 = is_aarch64_feature_detected!("sha3");
ArchCapabilities {
has_aes,
has_crc,
has_sha3,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
}
}
#[inline(always)]
#[cfg(all(target_arch = "aarch64", not(feature = "std")))]
unsafe fn detect_aarch64_features() -> ArchCapabilities {
ArchCapabilities {
has_aes: cfg!(target_feature = "aes"),
has_crc: cfg!(target_feature = "crc"),
has_sha3: cfg!(target_feature = "sha3"),
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
}
}
#[inline(always)]
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "std"))]
unsafe fn detect_x86_features() -> ArchCapabilities {
use std::arch::is_x86_feature_detected;
let has_sse41 = is_x86_feature_detected!("sse4.1");
let has_pclmulqdq = has_sse41 && is_x86_feature_detected!("pclmulqdq");
let has_avx512vl = has_pclmulqdq && is_x86_feature_detected!("avx512vl");
let has_vpclmulqdq = has_avx512vl && is_x86_feature_detected!("vpclmulqdq");
let has_sse42 = is_x86_feature_detected!("sse4.2");
ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41,
has_sse42,
has_pclmulqdq,
has_avx512vl,
has_vpclmulqdq,
}
}
#[inline(always)]
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(feature = "std")))]
unsafe fn detect_x86_features() -> ArchCapabilities {
let has_sse41 = cfg!(target_feature = "sse4.1");
let has_sse42 = cfg!(target_feature = "sse4.2");
let has_pclmulqdq = has_sse41 && cfg!(target_feature = "pclmulqdq");
let has_avx512vl = has_pclmulqdq && cfg!(target_feature = "avx512vl");
let has_vpclmulqdq = has_avx512vl && cfg!(target_feature = "vpclmulqdq");
ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41,
has_sse42,
has_pclmulqdq,
has_avx512vl,
has_vpclmulqdq,
}
}
#[inline(always)]
#[allow(unused)]
pub(crate) fn select_performance_tier(capabilities: &ArchCapabilities) -> PerformanceTier {
#[cfg(target_arch = "aarch64")]
{
if capabilities.has_sha3 && capabilities.has_aes {
return PerformanceTier::AArch64AesSha3;
}
if capabilities.has_aes {
return PerformanceTier::AArch64Aes;
}
}
#[cfg(target_arch = "x86_64")]
{
if capabilities.has_vpclmulqdq {
return PerformanceTier::X86_64Avx512Vpclmulqdq;
}
if capabilities.has_avx512vl {
return PerformanceTier::X86_64Avx512Pclmulqdq;
}
if capabilities.has_pclmulqdq {
return PerformanceTier::X86_64SsePclmulqdq;
}
}
#[cfg(target_arch = "x86")]
{
if capabilities.has_pclmulqdq {
return PerformanceTier::X86SsePclmulqdq;
}
}
PerformanceTier::SoftwareTable
}
#[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
#[derive(Debug, Clone, Copy)]
pub enum ArchOpsInstance {
#[cfg(target_arch = "aarch64")]
Aarch64Aes(crate::arch::aarch64::aes::Aarch64AesOps),
#[cfg(target_arch = "aarch64")]
Aarch64AesSha3(crate::arch::aarch64::aes_sha3::Aarch64AesSha3Ops),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
X86SsePclmulqdq(crate::arch::x86::sse::X86SsePclmulqdqOps),
#[cfg(target_arch = "x86_64")]
X86_64Avx512Pclmulqdq(crate::arch::x86_64::avx512::X86_64Avx512PclmulqdqOps),
#[cfg(target_arch = "x86_64")]
X86_64Avx512Vpclmulqdq(crate::arch::x86_64::avx512_vpclmulqdq::X86_64Avx512VpclmulqdqOps),
SoftwareFallback,
}
#[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
impl ArchOpsInstance {
#[inline(always)]
pub fn get_tier(&self) -> PerformanceTier {
match self {
#[cfg(target_arch = "aarch64")]
ArchOpsInstance::Aarch64Aes(_) => PerformanceTier::AArch64Aes,
#[cfg(target_arch = "aarch64")]
ArchOpsInstance::Aarch64AesSha3(_) => PerformanceTier::AArch64AesSha3,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
ArchOpsInstance::X86SsePclmulqdq(_) => PerformanceTier::X86SsePclmulqdq,
#[cfg(target_arch = "x86_64")]
ArchOpsInstance::X86_64Avx512Pclmulqdq(_) => PerformanceTier::X86_64Avx512Pclmulqdq,
#[cfg(target_arch = "x86_64")]
ArchOpsInstance::X86_64Avx512Vpclmulqdq(_) => PerformanceTier::X86_64Avx512Vpclmulqdq,
ArchOpsInstance::SoftwareFallback => PerformanceTier::SoftwareTable,
}
}
#[cfg(all(
feature = "alloc",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
#[inline(always)]
pub fn get_target_string(&self) -> String {
tier_to_target_string(self.get_tier())
}
}
#[cfg(all(
feature = "std",
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
pub fn get_arch_ops() -> &'static ArchOpsInstance {
ARCH_OPS_INSTANCE.get_or_init(create_arch_ops)
}
#[cfg(all(
not(feature = "std"),
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")
))]
pub fn get_arch_ops() -> &'static ArchOpsInstance {
ARCH_OPS_INSTANCE.call_once(create_arch_ops)
}
#[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
fn create_arch_ops() -> ArchOpsInstance {
let capabilities = unsafe { detect_arch_capabilities() };
let tier = select_performance_tier(&capabilities);
create_arch_ops_from_tier(tier)
}
#[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
fn create_arch_ops_from_tier(tier: PerformanceTier) -> ArchOpsInstance {
match tier {
#[cfg(target_arch = "aarch64")]
PerformanceTier::AArch64AesSha3 => {
use crate::arch::aarch64::aes_sha3::Aarch64AesSha3Ops;
ArchOpsInstance::Aarch64AesSha3(Aarch64AesSha3Ops::new())
}
#[cfg(target_arch = "aarch64")]
PerformanceTier::AArch64Aes => {
use crate::arch::aarch64::aes::Aarch64AesOps;
ArchOpsInstance::Aarch64Aes(Aarch64AesOps)
}
#[cfg(target_arch = "x86_64")]
PerformanceTier::X86_64Avx512Vpclmulqdq => {
use crate::arch::x86_64::avx512_vpclmulqdq::X86_64Avx512VpclmulqdqOps;
ArchOpsInstance::X86_64Avx512Vpclmulqdq(X86_64Avx512VpclmulqdqOps::new())
}
#[cfg(target_arch = "x86_64")]
PerformanceTier::X86_64Avx512Pclmulqdq => {
use crate::arch::x86_64::avx512::X86_64Avx512PclmulqdqOps;
ArchOpsInstance::X86_64Avx512Pclmulqdq(X86_64Avx512PclmulqdqOps::new())
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
PerformanceTier::X86_64SsePclmulqdq | PerformanceTier::X86SsePclmulqdq => {
create_x86_sse_pclmulqdq_ops()
}
PerformanceTier::SoftwareTable => {
ArchOpsInstance::SoftwareFallback
}
_ => {
ArchOpsInstance::SoftwareFallback
}
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn create_x86_sse_pclmulqdq_ops() -> ArchOpsInstance {
use crate::arch::x86::sse::X86SsePclmulqdqOps;
ArchOpsInstance::X86SsePclmulqdq(X86SsePclmulqdqOps)
}
#[cfg(test)]
pub fn select_performance_tier_for_test(capabilities: &ArchCapabilities) -> PerformanceTier {
if capabilities.has_sha3 && capabilities.has_aes {
return PerformanceTier::AArch64AesSha3;
}
if capabilities.has_aes {
return PerformanceTier::AArch64Aes;
}
if capabilities.has_vpclmulqdq && capabilities.has_avx512vl {
return PerformanceTier::X86_64Avx512Vpclmulqdq;
}
if capabilities.has_avx512vl && capabilities.has_pclmulqdq {
return PerformanceTier::X86_64Avx512Pclmulqdq;
}
if capabilities.has_pclmulqdq && capabilities.has_sse41 {
return PerformanceTier::X86_64SsePclmulqdq;
}
PerformanceTier::SoftwareTable
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_aarch64_tier_selection() {
let capabilities_sha3 = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: true,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_sha3),
PerformanceTier::AArch64AesSha3
);
let capabilities_aes = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_aes),
PerformanceTier::AArch64Aes
);
let capabilities_no_aes = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_no_aes),
PerformanceTier::SoftwareTable
);
}
#[test]
fn test_aarch64_feature_hierarchy() {
let capabilities_with_aes = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert!(capabilities_with_aes.has_aes);
let capabilities_with_sha3 = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: true,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert!(capabilities_with_sha3.has_aes);
assert!(capabilities_with_sha3.has_sha3);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_x86_64_tier_selection() {
let capabilities_vpclmulqdq = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: true,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_vpclmulqdq),
PerformanceTier::X86_64Avx512Vpclmulqdq
);
let capabilities_avx512 = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_avx512),
PerformanceTier::X86_64Avx512Pclmulqdq
);
let capabilities_sse = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_sse),
PerformanceTier::X86_64SsePclmulqdq
);
let capabilities_no_pclmul = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_no_pclmul),
PerformanceTier::SoftwareTable
);
}
#[test]
#[cfg(target_arch = "x86")]
fn test_x86_tier_selection() {
let capabilities_sse = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_sse),
PerformanceTier::X86_64SsePclmulqdq
);
let capabilities_x86_sse = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false, has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_x86_sse),
PerformanceTier::X86_64SsePclmulqdq
);
let capabilities_no_pclmul = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities_no_pclmul),
PerformanceTier::SoftwareTable
);
}
#[test]
fn test_x86_feature_hierarchy() {
let capabilities_full = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: true,
};
assert!(capabilities_full.has_sse41);
assert!(capabilities_full.has_pclmulqdq);
assert!(capabilities_full.has_avx512vl);
assert!(capabilities_full.has_vpclmulqdq);
}
mod mock_feature_agreement_tests {
use super::*;
#[test]
fn test_feature_dependency_validation() {
let invalid_sha3_caps = ArchCapabilities {
has_aes: false, has_crc: false,
has_sha3: true, has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&invalid_sha3_caps),
PerformanceTier::SoftwareTable
);
let invalid_vpclmul_caps = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false, has_vpclmulqdq: true, };
assert_eq!(
select_performance_tier_for_test(&invalid_vpclmul_caps),
PerformanceTier::X86_64SsePclmulqdq
);
}
}
mod tier_selection_comprehensive_tests {
use super::*;
#[test]
fn test_all_aarch64_tier_combinations() {
let no_features = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&no_features),
PerformanceTier::SoftwareTable
);
let aes_only = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&aes_only),
PerformanceTier::AArch64Aes
);
let aes_sha3 = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: true,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&aes_sha3),
PerformanceTier::AArch64AesSha3
);
}
#[test]
fn test_all_x86_64_tier_combinations() {
let no_features = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&no_features),
PerformanceTier::SoftwareTable
);
let sse_only = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&sse_only),
PerformanceTier::SoftwareTable
);
let sse_pclmul = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&sse_pclmul),
PerformanceTier::X86_64SsePclmulqdq
);
let avx512_pclmul_new_rust = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&avx512_pclmul_new_rust),
PerformanceTier::X86_64Avx512Pclmulqdq
);
let all_features_new_rust = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: true,
};
assert_eq!(
select_performance_tier_for_test(&all_features_new_rust),
PerformanceTier::X86_64Avx512Vpclmulqdq
);
}
#[test]
fn test_x86_32bit_tier_combinations() {
let no_features = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&no_features),
PerformanceTier::SoftwareTable
);
let sse_pclmul = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false, has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&sse_pclmul),
PerformanceTier::X86_64SsePclmulqdq
);
}
#[test]
fn test_target_string_consistency() {
let test_cases = [
(PerformanceTier::AArch64AesSha3, "aarch64-neon-pmull-sha3"),
(PerformanceTier::AArch64Aes, "aarch64-neon-pmull"),
(
PerformanceTier::X86_64Avx512Vpclmulqdq,
"x86_64-avx512-vpclmulqdq",
),
(
PerformanceTier::X86_64Avx512Pclmulqdq,
"x86_64-avx512-pclmulqdq",
),
(PerformanceTier::X86_64SsePclmulqdq, "x86_64-sse-pclmulqdq"),
(PerformanceTier::X86SsePclmulqdq, "x86-sse-pclmulqdq"),
(PerformanceTier::SoftwareTable, "software-fallback-tables"),
];
for (tier, expected_string) in test_cases {
assert_eq!(tier_to_target_string(tier), expected_string);
}
}
}
mod graceful_degradation_tests {
use super::*;
#[test]
fn test_aarch64_degradation_path() {
let mut capabilities = ArchCapabilities {
has_aes: true,
has_crc: false,
has_sha3: true,
has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::AArch64AesSha3
);
capabilities.has_sha3 = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::AArch64Aes
);
capabilities.has_aes = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::SoftwareTable
);
}
#[test]
fn test_x86_64_degradation_path() {
let mut capabilities = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: true,
has_vpclmulqdq: true,
};
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::X86_64Avx512Vpclmulqdq
);
capabilities.has_vpclmulqdq = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::X86_64Avx512Pclmulqdq
);
capabilities.has_avx512vl = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::X86_64SsePclmulqdq
);
capabilities.has_pclmulqdq = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::SoftwareTable
);
capabilities.has_sse41 = false;
assert_eq!(
select_performance_tier_for_test(&capabilities),
PerformanceTier::SoftwareTable
);
}
#[test]
fn test_partial_feature_availability() {
let aarch64_partial = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: true, has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
assert_eq!(
select_performance_tier_for_test(&aarch64_partial),
PerformanceTier::SoftwareTable
);
let x86_64_partial = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true,
has_sse42: false,
has_pclmulqdq: true,
has_avx512vl: false,
has_vpclmulqdq: true, };
assert_eq!(
select_performance_tier_for_test(&x86_64_partial),
PerformanceTier::X86_64SsePclmulqdq
);
}
}
}
#[cfg(test)]
mod software_fallback_tests {
use super::*;
#[test]
fn test_aarch64_without_aes_falls_back_to_software() {
let capabilities_no_aes = ArchCapabilities {
has_aes: false, has_crc: false,
has_sha3: false, has_sse41: false,
has_sse42: false,
has_pclmulqdq: false,
has_avx512vl: false,
has_vpclmulqdq: false,
};
let tier = select_performance_tier_for_test(&capabilities_no_aes);
assert_eq!(
tier,
PerformanceTier::SoftwareTable,
"AArch64 without AES should fall back to software implementation"
);
}
#[test]
fn test_x86_without_pclmulqdq_falls_back_to_software() {
let capabilities_no_pclmul = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: true, has_sse42: false,
has_pclmulqdq: false, has_avx512vl: false,
has_vpclmulqdq: false,
};
let tier = select_performance_tier_for_test(&capabilities_no_pclmul);
assert_eq!(
tier,
PerformanceTier::SoftwareTable,
"x86 without PCLMULQDQ should fall back to software implementation"
);
let capabilities_no_sse = ArchCapabilities {
has_aes: false,
has_crc: false,
has_sha3: false,
has_sse41: false, has_sse42: false,
has_pclmulqdq: false, has_avx512vl: false,
has_vpclmulqdq: false,
};
let tier = select_performance_tier_for_test(&capabilities_no_sse);
assert_eq!(
tier,
PerformanceTier::SoftwareTable,
"x86 without SSE4.1 should fall back to software implementation"
);
}
#[test]
fn test_conditional_compilation_coverage() {
#[cfg(any(
not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")),
target_arch = "x86",
all(target_arch = "aarch64", not(target_feature = "aes"))
))]
{
use crate::arch::software;
let _test_fn = software::update;
}
}
}