#![allow(clippy::unused_unit, clippy::use_self)]
use crate::error::ParseCpuFeatureError;
use enumset::{EnumSet, EnumSetType};
use std::str::FromStr;
pub use target_lexicon::{
Aarch64Architecture, Architecture, BinaryFormat, CallingConvention, Endianness, Environment,
OperatingSystem, PointerWidth, Triple, Vendor,
};
#[allow(missing_docs, clippy::derived_hash_with_manual_eq)]
#[derive(EnumSetType, Debug, Hash)]
pub enum CpuFeature {
SSE2,
SSE3,
SSSE3,
SSE41,
SSE42,
POPCNT,
AVX,
BMI1,
BMI2,
AVX2,
AVX512DQ,
AVX512VL,
AVX512F,
LZCNT,
FMA,
NEON,
}
impl CpuFeature {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn for_host() -> EnumSet<Self> {
let mut features = EnumSet::new();
if std::is_x86_feature_detected!("sse2") {
features.insert(Self::SSE2);
}
if std::is_x86_feature_detected!("sse3") {
features.insert(Self::SSE3);
}
if std::is_x86_feature_detected!("ssse3") {
features.insert(Self::SSSE3);
}
if std::is_x86_feature_detected!("sse4.1") {
features.insert(Self::SSE41);
}
if std::is_x86_feature_detected!("sse4.2") {
features.insert(Self::SSE42);
}
if std::is_x86_feature_detected!("popcnt") {
features.insert(Self::POPCNT);
}
if std::is_x86_feature_detected!("avx") {
features.insert(Self::AVX);
}
if std::is_x86_feature_detected!("bmi1") {
features.insert(Self::BMI1);
}
if std::is_x86_feature_detected!("bmi2") {
features.insert(Self::BMI2);
}
if std::is_x86_feature_detected!("avx2") {
features.insert(Self::AVX2);
}
if std::is_x86_feature_detected!("fma") {
features.insert(Self::FMA);
}
if std::is_x86_feature_detected!("avx512dq") {
features.insert(Self::AVX512DQ);
}
if std::is_x86_feature_detected!("avx512vl") {
features.insert(Self::AVX512VL);
}
if std::is_x86_feature_detected!("avx512f") {
features.insert(Self::AVX512F);
}
if std::is_x86_feature_detected!("lzcnt") {
features.insert(Self::LZCNT);
}
features
}
#[cfg(target_arch = "aarch64")]
pub fn for_host() -> EnumSet<Self> {
let mut features = EnumSet::new();
if std::arch::is_aarch64_feature_detected!("neon") {
features.insert(Self::NEON);
}
features
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
pub fn for_host() -> EnumSet<Self> {
EnumSet::new()
}
pub fn set() -> EnumSet<Self> {
EnumSet::new()
}
pub fn all() -> EnumSet<Self> {
EnumSet::all()
}
}
impl FromStr for CpuFeature {
type Err = ParseCpuFeatureError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"sse2" => Ok(Self::SSE2),
"sse3" => Ok(Self::SSE3),
"ssse3" => Ok(Self::SSSE3),
"sse4.1" => Ok(Self::SSE41),
"sse4.2" => Ok(Self::SSE42),
"popcnt" => Ok(Self::POPCNT),
"avx" => Ok(Self::AVX),
"bmi" => Ok(Self::BMI1),
"bmi2" => Ok(Self::BMI2),
"avx2" => Ok(Self::AVX2),
"fma" => Ok(Self::FMA),
"avx512dq" => Ok(Self::AVX512DQ),
"avx512vl" => Ok(Self::AVX512VL),
"avx512f" => Ok(Self::AVX512F),
"lzcnt" => Ok(Self::LZCNT),
"neon" => Ok(Self::NEON),
_ => Err(ParseCpuFeatureError::Missing(s.to_string())),
}
}
}
impl std::fmt::Display for CpuFeature {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}",
match self {
Self::SSE2 => "sse2",
Self::SSE3 => "sse3",
Self::SSSE3 => "ssse3",
Self::SSE41 => "sse4.1",
Self::SSE42 => "sse4.2",
Self::POPCNT => "popcnt",
Self::AVX => "avx",
Self::BMI1 => "bmi",
Self::BMI2 => "bmi2",
Self::AVX2 => "avx2",
Self::FMA => "fma",
Self::AVX512DQ => "avx512dq",
Self::AVX512VL => "avx512vl",
Self::AVX512F => "avx512f",
Self::LZCNT => "lzcnt",
Self::NEON => "neon",
}
)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Target {
triple: Triple,
cpu_features: EnumSet<CpuFeature>,
}
impl Target {
pub fn new(triple: Triple, cpu_features: EnumSet<CpuFeature>) -> Self {
Self {
triple,
cpu_features,
}
}
pub fn triple(&self) -> &Triple {
&self.triple
}
pub fn cpu_features(&self) -> &EnumSet<CpuFeature> {
&self.cpu_features
}
pub fn is_native(&self) -> bool {
let host = Triple::host();
host.operating_system == self.triple.operating_system
&& host.architecture == self.triple.architecture
}
}
impl Default for Target {
fn default() -> Self {
Self {
triple: Triple::host(),
cpu_features: CpuFeature::for_host(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct UserCompilerOptimizations {
pub pass_params: Option<bool>,
}