use std::collections::HashSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86SchedModel {
Generic,
P6,
NetBurst,
Core2,
Nehalem,
SandyBridge,
IvyBridge,
Haswell,
Broadwell,
SkylakeClient,
SkylakeServer,
CascadeLake,
CooperLake,
CannonLake,
IceLakeClient,
IceLakeServer,
TigerLake,
SapphireRapids,
EmeraldRapids,
GraniteRapids,
AlderLake,
RocketLake,
MeteorLake,
ArrowLake,
LunarLake,
Bonnell,
Silvermont,
Goldmont,
GoldmontPlus,
Tremont,
Gracemont,
KnightsLanding,
K8,
K10,
Bobcat,
Jaguar,
Bulldozer,
Piledriver,
Steamroller,
Excavator,
Zen1,
Zen2,
Zen3,
Zen4,
Zen5,
}
impl X86SchedModel {
pub fn name(&self) -> &'static str {
match self {
X86SchedModel::Generic => "Generic",
X86SchedModel::P6 => "P6",
X86SchedModel::NetBurst => "NetBurst",
X86SchedModel::Core2 => "Core2",
X86SchedModel::Nehalem => "Nehalem",
X86SchedModel::SandyBridge => "SandyBridge",
X86SchedModel::IvyBridge => "IvyBridge",
X86SchedModel::Haswell => "Haswell",
X86SchedModel::Broadwell => "Broadwell",
X86SchedModel::SkylakeClient => "SkylakeClient",
X86SchedModel::SkylakeServer => "SkylakeServer",
X86SchedModel::CascadeLake => "CascadeLake",
X86SchedModel::CooperLake => "CooperLake",
X86SchedModel::CannonLake => "CannonLake",
X86SchedModel::IceLakeClient => "IceLakeClient",
X86SchedModel::IceLakeServer => "IceLakeServer",
X86SchedModel::TigerLake => "TigerLake",
X86SchedModel::SapphireRapids => "SapphireRapids",
X86SchedModel::EmeraldRapids => "EmeraldRapids",
X86SchedModel::GraniteRapids => "GraniteRapids",
X86SchedModel::AlderLake => "AlderLake",
X86SchedModel::RocketLake => "RocketLake",
X86SchedModel::MeteorLake => "MeteorLake",
X86SchedModel::ArrowLake => "ArrowLake",
X86SchedModel::LunarLake => "LunarLake",
X86SchedModel::Bonnell => "Bonnell",
X86SchedModel::Silvermont => "Silvermont",
X86SchedModel::Goldmont => "Goldmont",
X86SchedModel::GoldmontPlus => "GoldmontPlus",
X86SchedModel::Tremont => "Tremont",
X86SchedModel::Gracemont => "Gracemont",
X86SchedModel::KnightsLanding => "KnightsLanding",
X86SchedModel::K8 => "K8",
X86SchedModel::K10 => "K10",
X86SchedModel::Bobcat => "Bobcat",
X86SchedModel::Jaguar => "Jaguar",
X86SchedModel::Bulldozer => "Bulldozer",
X86SchedModel::Piledriver => "Piledriver",
X86SchedModel::Steamroller => "Steamroller",
X86SchedModel::Excavator => "Excavator",
X86SchedModel::Zen1 => "Zen1",
X86SchedModel::Zen2 => "Zen2",
X86SchedModel::Zen3 => "Zen3",
X86SchedModel::Zen4 => "Zen4",
X86SchedModel::Zen5 => "Zen5",
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct X86SchedInfo {
pub dispatch: u32,
pub issue: u32,
pub retire: u32,
pub rob_size: u32,
pub ld_buf: u32,
pub st_buf: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct X86Subtarget {
pub cpu: String,
pub features: HashSet<String>,
pub is_64_bit: bool,
pub has_sse: bool,
pub has_sse2: bool,
pub has_sse3: bool,
pub has_ssse3: bool,
pub has_sse41: bool,
pub has_sse42: bool,
pub has_avx: bool,
pub has_avx2: bool,
pub has_avx512f: bool,
pub has_avx512bw: bool,
pub has_avx512dq: bool,
pub has_avx512vl: bool,
pub has_fma: bool,
pub has_f16c: bool,
pub has_bmi: bool,
pub has_bmi2: bool,
pub has_lzcnt: bool,
pub has_popcnt: bool,
pub has_mmx: bool,
pub has_3dnow: bool,
pub has_x87: bool,
pub has_cmov: bool,
pub has_fxr: bool,
pub has_nopl: bool,
pub has_sahf: bool,
pub has_lahf_sahf: bool,
pub has_rtm: bool,
pub has_adx: bool,
pub has_sha: bool,
pub has_sgx: bool,
pub has_cet: bool,
pub has_xsave: bool,
pub has_xsaveopt: bool,
pub has_xsavec: bool,
pub has_xsaves: bool,
pub has_movbe: bool,
pub has_rdrnd: bool,
pub has_rdseed: bool,
pub has_prfchw: bool,
pub has_mwaitx: bool,
pub has_clzero: bool,
pub has_clwb: bool,
pub has_pku: bool,
pub has_vaes: bool,
pub has_vpclmulqdq: bool,
pub has_gfni: bool,
pub stack_alignment: u32,
pub max_inline_size_threshold: u32,
pub pref_vector_width: u32,
pub use_soft_float: bool,
pub has_aes: bool,
pub has_pclmul: bool,
pub has_fsgsbase: bool,
pub has_tbm: bool,
pub has_hle: bool,
pub has_clflushopt: bool,
pub has_prefetchwt1: bool,
pub has_invpcid: bool,
pub has_smap: bool,
pub has_smep: bool,
pub has_mpx: bool,
pub has_pt: bool,
pub has_waitpkg: bool,
pub has_cldemote: bool,
pub has_movdiri: bool,
pub has_movdir64b: bool,
pub has_enqcmd: bool,
pub has_serialize: bool,
pub has_tsxldtrk: bool,
pub has_uintr: bool,
pub has_amx_bf16: bool,
pub has_amx_int8: bool,
pub has_amx_tile: bool,
pub has_amx_fp16: bool,
pub has_avx_vnni: bool,
pub has_avx_ifma: bool,
pub has_avx_ne_convert: bool,
pub has_avx_vnni_int8: bool,
pub has_cmpccxadd: bool,
pub has_prefetchiti: bool,
pub has_raoint: bool,
pub has_sha512: bool,
pub has_sm3: bool,
pub has_sm4: bool,
pub has_hreset: bool,
pub has_kl: bool,
pub has_widekl: bool,
pub has_xop: bool,
pub has_fma4: bool,
pub pad_short_functions: bool,
pub opt_for_size: bool,
pub opt_for_speed: bool,
pub slow_unaligned_mem_16: bool,
pub slow_unaligned_mem_32: bool,
pub slow_divide_32: bool,
pub slow_divide_64: bool,
pub lea_uses_ag: bool,
pub use_inc_dec: bool,
pub use_sqrt_estimate: bool,
pub use_reciprocal_estimate: bool,
pub use_div_eq_delay: bool,
pub use_cmov_branch: bool,
pub use_bsr: bool,
pub dispatch_width: u32,
pub issue_width: u32,
pub retire_width: u32,
pub reorder_buffer_size: u32,
pub load_buffer_size: u32,
pub store_buffer_size: u32,
pub schedule_model: X86SchedModel,
}
impl Default for X86Subtarget {
fn default() -> Self {
Self::new("x86_64-unknown-linux-gnu", "generic", "")
}
}
impl X86Subtarget {
pub fn new(triple: &str, cpu: &str, features: &str) -> Self {
let is_64_bit = triple_is_64_bit(triple);
let mut feature_set = features_for_cpu(cpu);
if is_64_bit {
feature_set.insert("sse2".to_string());
feature_set.insert("cmov".to_string());
}
parse_feature_string(&mut feature_set, features);
let has_sse = feature_set.contains("sse");
let has_sse2 = feature_set.contains("sse2");
let has_sse3 = feature_set.contains("sse3");
let has_ssse3 = feature_set.contains("ssse3");
let has_sse41 = feature_set.contains("sse4.1");
let has_sse42 = feature_set.contains("sse4.2");
let has_avx = feature_set.contains("avx");
let has_avx2 = feature_set.contains("avx2");
let has_avx512f = feature_set.contains("avx512f");
let has_avx512bw = feature_set.contains("avx512bw");
let has_avx512dq = feature_set.contains("avx512dq");
let has_avx512vl = feature_set.contains("avx512vl");
let has_fma = feature_set.contains("fma");
let has_f16c = feature_set.contains("f16c");
let has_bmi = feature_set.contains("bmi");
let has_bmi2 = feature_set.contains("bmi2");
let has_lzcnt = feature_set.contains("lzcnt");
let has_popcnt = feature_set.contains("popcnt");
let has_mmx = feature_set.contains("mmx");
let has_3dnow = feature_set.contains("3dnow");
let has_x87 = feature_set.contains("x87");
let has_cmov = feature_set.contains("cmov");
let has_fxr = feature_set.contains("fxr");
let has_nopl = feature_set.contains("nopl");
let has_sahf = feature_set.contains("sahf");
let has_lahf_sahf = feature_set.contains("lahf_sahf");
let has_rtm = feature_set.contains("rtm");
let has_adx = feature_set.contains("adx");
let has_sha = feature_set.contains("sha");
let has_sgx = feature_set.contains("sgx");
let has_cet = feature_set.contains("cet");
let has_xsave = feature_set.contains("xsave");
let has_xsaveopt = feature_set.contains("xsaveopt");
let has_xsavec = feature_set.contains("xsavec");
let has_xsaves = feature_set.contains("xsaves");
let has_movbe = feature_set.contains("movbe");
let has_rdrnd = feature_set.contains("rdrnd");
let has_rdseed = feature_set.contains("rdseed");
let has_prfchw = feature_set.contains("prfchw");
let has_mwaitx = feature_set.contains("mwaitx");
let has_clzero = feature_set.contains("clzero");
let has_clwb = feature_set.contains("clwb");
let has_pku = feature_set.contains("pku");
let has_vaes = feature_set.contains("vaes");
let has_vpclmulqdq = feature_set.contains("vpclmulqdq");
let has_gfni = feature_set.contains("gfni");
let has_aes = feature_set.contains("aes");
let has_pclmul = feature_set.contains("pclmul");
let has_fsgsbase = feature_set.contains("fsgsbase");
let has_tbm = feature_set.contains("tbm");
let has_hle = feature_set.contains("hle");
let has_clflushopt = feature_set.contains("clflushopt");
let has_prefetchwt1 = feature_set.contains("prefetchwt1");
let has_invpcid = feature_set.contains("invpcid");
let has_smap = feature_set.contains("smap");
let has_smep = feature_set.contains("smep");
let has_mpx = feature_set.contains("mpx");
let has_pt = feature_set.contains("pt");
let has_waitpkg = feature_set.contains("waitpkg");
let has_cldemote = feature_set.contains("cldemote");
let has_movdiri = feature_set.contains("movdiri");
let has_movdir64b = feature_set.contains("movdir64b");
let has_enqcmd = feature_set.contains("enqcmd");
let has_serialize = feature_set.contains("serialize");
let has_tsxldtrk = feature_set.contains("tsxldtrk");
let has_uintr = feature_set.contains("uintr");
let has_amx_bf16 = feature_set.contains("amx-bf16");
let has_amx_int8 = feature_set.contains("amx-int8");
let has_amx_tile = feature_set.contains("amx-tile");
let has_amx_fp16 = feature_set.contains("amx-fp16");
let has_avx_vnni = feature_set.contains("avx-vnni");
let has_avx_ifma = feature_set.contains("avx-ifma");
let has_avx_ne_convert = feature_set.contains("avx-ne-convert");
let has_avx_vnni_int8 = feature_set.contains("avx-vnni-int8");
let has_cmpccxadd = feature_set.contains("cmpccxadd");
let has_prefetchiti = feature_set.contains("prefetchiti");
let has_raoint = feature_set.contains("rao-int");
let has_sha512 = feature_set.contains("sha512");
let has_sm3 = feature_set.contains("sm3");
let has_sm4 = feature_set.contains("sm4");
let has_hreset = feature_set.contains("hreset");
let has_kl = feature_set.contains("kl");
let has_widekl = feature_set.contains("widekl");
let has_xop = feature_set.contains("xop");
let has_fma4 = feature_set.contains("fma4");
let (
pad_short_functions,
opt_for_size,
opt_for_speed,
slow_unaligned_mem_16,
slow_unaligned_mem_32,
slow_divide_32,
slow_divide_64,
lea_uses_ag,
use_inc_dec,
use_sqrt_estimate,
use_reciprocal_estimate,
use_div_eq_delay,
use_cmov_branch,
use_bsr,
) = tuning_flags_for_cpu(cpu, is_64_bit);
let schedule_model = sched_model_for_cpu(cpu);
let sched = sched_info_for_model(schedule_model);
let stack_alignment = if is_64_bit || has_avx { 16 } else { 4 };
let pref_vector_width = if has_avx512f {
512
} else if has_avx {
256
} else if has_sse2 {
128
} else {
0
};
let max_inline_size_threshold = default_inline_threshold(cpu);
X86Subtarget {
cpu: cpu.to_string(),
features: feature_set,
is_64_bit,
has_sse,
has_sse2,
has_sse3,
has_ssse3,
has_sse41,
has_sse42,
has_avx,
has_avx2,
has_avx512f,
has_avx512bw,
has_avx512dq,
has_avx512vl,
has_fma,
has_f16c,
has_bmi,
has_bmi2,
has_lzcnt,
has_popcnt,
has_mmx,
has_3dnow,
has_x87,
has_cmov,
has_fxr,
has_nopl,
has_sahf,
has_lahf_sahf,
has_rtm,
has_adx,
has_sha,
has_sgx,
has_cet,
has_xsave,
has_xsaveopt,
has_xsavec,
has_xsaves,
has_movbe,
has_rdrnd,
has_rdseed,
has_prfchw,
has_mwaitx,
has_clzero,
has_clwb,
has_pku,
has_vaes,
has_vpclmulqdq,
has_gfni,
has_aes,
has_pclmul,
has_fsgsbase,
has_tbm,
has_hle,
has_clflushopt,
has_prefetchwt1,
has_invpcid,
has_smap,
has_smep,
has_mpx,
has_pt,
has_waitpkg,
has_cldemote,
has_movdiri,
has_movdir64b,
has_enqcmd,
has_serialize,
has_tsxldtrk,
has_uintr,
has_amx_bf16,
has_amx_int8,
has_amx_tile,
has_amx_fp16,
has_avx_vnni,
has_avx_ifma,
has_avx_ne_convert,
has_avx_vnni_int8,
has_cmpccxadd,
has_prefetchiti,
has_raoint,
has_sha512,
has_sm3,
has_sm4,
has_hreset,
has_kl,
has_widekl,
has_xop,
has_fma4,
pad_short_functions,
opt_for_size,
opt_for_speed,
slow_unaligned_mem_16,
slow_unaligned_mem_32,
slow_divide_32,
slow_divide_64,
lea_uses_ag,
use_inc_dec,
use_sqrt_estimate,
use_reciprocal_estimate,
use_div_eq_delay,
use_cmov_branch,
use_bsr,
dispatch_width: sched.dispatch,
issue_width: sched.issue,
retire_width: sched.retire,
reorder_buffer_size: sched.rob_size,
load_buffer_size: sched.ld_buf,
store_buffer_size: sched.st_buf,
schedule_model,
stack_alignment,
max_inline_size_threshold,
pref_vector_width,
use_soft_float: false,
}
}
#[inline]
pub fn in_64bit_mode(&self) -> bool {
self.is_64_bit
}
#[inline]
pub fn in_32bit_mode(&self) -> bool {
!self.is_64_bit
}
#[inline]
pub fn has_sse(&self) -> bool {
self.has_sse
}
#[inline]
pub fn has_sse2(&self) -> bool {
self.has_sse2
}
#[inline]
pub fn has_sse3(&self) -> bool {
self.has_sse3
}
#[inline]
pub fn has_ssse3(&self) -> bool {
self.has_ssse3
}
#[inline]
pub fn has_sse41(&self) -> bool {
self.has_sse41
}
#[inline]
pub fn has_sse42(&self) -> bool {
self.has_sse42
}
#[inline]
pub fn has_avx(&self) -> bool {
self.has_avx
}
#[inline]
pub fn has_avx2(&self) -> bool {
self.has_avx2
}
#[inline]
pub fn has_avx512f(&self) -> bool {
self.has_avx512f
}
#[inline]
pub fn has_avx512bw(&self) -> bool {
self.has_avx512bw
}
#[inline]
pub fn has_avx512dq(&self) -> bool {
self.has_avx512dq
}
#[inline]
pub fn has_avx512vl(&self) -> bool {
self.has_avx512vl
}
#[inline]
pub fn has_avx512(&self) -> bool {
self.has_avx512f
}
#[inline]
pub fn has_fma(&self) -> bool {
self.has_fma
}
#[inline]
pub fn has_f16c(&self) -> bool {
self.has_f16c
}
#[inline]
pub fn has_bmi(&self) -> bool {
self.has_bmi
}
#[inline]
pub fn has_bmi2(&self) -> bool {
self.has_bmi2
}
#[inline]
pub fn has_lzcnt(&self) -> bool {
self.has_lzcnt
}
#[inline]
pub fn has_popcnt(&self) -> bool {
self.has_popcnt
}
#[inline]
pub fn has_mmx(&self) -> bool {
self.has_mmx
}
#[inline]
pub fn has_3dnow(&self) -> bool {
self.has_3dnow
}
#[inline]
pub fn has_x87(&self) -> bool {
self.has_x87
}
#[inline]
pub fn has_cmov(&self) -> bool {
self.has_cmov
}
#[inline]
pub fn has_rtm(&self) -> bool {
self.has_rtm
}
#[inline]
pub fn has_adx(&self) -> bool {
self.has_adx
}
#[inline]
pub fn has_sha(&self) -> bool {
self.has_sha
}
#[inline]
pub fn has_sgx(&self) -> bool {
self.has_sgx
}
#[inline]
pub fn has_cet(&self) -> bool {
self.has_cet
}
#[inline]
pub fn has_xsave(&self) -> bool {
self.has_xsave
}
#[inline]
pub fn has_movbe(&self) -> bool {
self.has_movbe
}
#[inline]
pub fn has_rdrnd(&self) -> bool {
self.has_rdrnd
}
#[inline]
pub fn has_rdseed(&self) -> bool {
self.has_rdseed
}
#[inline]
pub fn has_vaes(&self) -> bool {
self.has_vaes
}
#[inline]
pub fn has_vpclmulqdq(&self) -> bool {
self.has_vpclmulqdq
}
#[inline]
pub fn has_gfni(&self) -> bool {
self.has_gfni
}
#[inline]
pub fn has_clzero(&self) -> bool {
self.has_clzero
}
#[inline]
pub fn has_mwaitx(&self) -> bool {
self.has_mwaitx
}
#[inline]
pub fn has_clwb(&self) -> bool {
self.has_clwb
}
#[inline]
pub fn has_pku(&self) -> bool {
self.has_pku
}
#[inline]
pub fn get_stack_alignment(&self) -> u32 {
self.stack_alignment
}
#[inline]
pub fn get_pref_vector_width(&self) -> u32 {
self.pref_vector_width
}
#[inline]
pub fn get_max_inline_size_threshold(&self) -> u32 {
self.max_inline_size_threshold
}
#[inline]
pub fn use_soft_float(&self) -> bool {
self.use_soft_float
}
#[inline]
pub fn has_feature(&self, flag: &str) -> bool {
self.features.contains(flag)
}
pub fn get_feature_set(&self) -> &HashSet<String> {
&self.features
}
pub fn feature_string(&self) -> String {
let mut flags: Vec<&str> = Vec::new();
if self.has_sse {
flags.push("sse");
}
if self.has_sse2 {
flags.push("sse2");
}
if self.has_sse3 {
flags.push("sse3");
}
if self.has_ssse3 {
flags.push("ssse3");
}
if self.has_sse41 {
flags.push("sse4.1");
}
if self.has_sse42 {
flags.push("sse4.2");
}
if self.has_avx {
flags.push("avx");
}
if self.has_avx2 {
flags.push("avx2");
}
if self.has_avx512f {
flags.push("avx512f");
}
if self.has_avx512bw {
flags.push("avx512bw");
}
if self.has_avx512dq {
flags.push("avx512dq");
}
if self.has_avx512vl {
flags.push("avx512vl");
}
if self.has_fma {
flags.push("fma");
}
if self.has_f16c {
flags.push("f16c");
}
if self.has_bmi {
flags.push("bmi");
}
if self.has_bmi2 {
flags.push("bmi2");
}
if self.has_lzcnt {
flags.push("lzcnt");
}
if self.has_popcnt {
flags.push("popcnt");
}
if self.has_mmx {
flags.push("mmx");
}
if self.has_3dnow {
flags.push("3dnow");
}
if self.has_x87 {
flags.push("x87");
}
if self.has_cmov {
flags.push("cmov");
}
if self.has_rtm {
flags.push("rtm");
}
if self.has_adx {
flags.push("adx");
}
if self.has_sha {
flags.push("sha");
}
if self.has_sgx {
flags.push("sgx");
}
if self.has_cet {
flags.push("cet");
}
if flags.is_empty() {
"none".to_string()
} else {
flags.join(",")
}
}
}
#[allow(clippy::too_many_arguments)]
fn tuning_flags_for_cpu(
cpu: &str,
_is_64_bit: bool,
) -> (
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
) {
let cpu_lower = cpu.to_lowercase();
match cpu_lower.as_str() {
"skylake" | "skylake-avx512" | "cascadelake" | "cooperlake" | "icelake-client"
| "icelake-server" | "cannonlake" | "rocketlake" | "tigerlake" | "alderlake"
| "sapphirerapids" | "emeraldrapids" | "graniterapids" | "graniterapids-d"
| "meteorlake" | "arrowlake" | "lunarlake" | "pantherlake" => {
(
false, false, false, false, false, false, false, true, false, false, false, true,
false, true,
)
}
"haswell" | "broadwell" => (
false, false, false, false, false, false, false, true, false, false, false, true,
false, true,
),
"sandybridge" | "ivybridge" => (
false, false, false, false, false, false, true, true, false, false, false, true, false,
true,
),
"nehalem" | "westmere" => (
false, false, false, false, true, true, true, false, false, false, false, true, false,
true,
),
"core2" | "penryn" => (
false, false, true, true, true, true, true, false, false, false, false, false, false,
true,
),
"pentium4" | "pentium4m" => (
false, false, true, true, true, true, false, false, false, true, false, false, false,
true,
),
"atom" | "bonnell" => (
false, true, true, true, true, true, true, false, false, false, false, false, false,
false,
),
"silvermont" | "slm" | "goldmont" | "glm" | "goldmont-plus" | "glp" => (
false, false, false, false, false, false, false, false, false, false, false, true,
false, false,
),
"tremont" | "tnt" | "gracemont" => (
false, false, false, false, false, false, false, true, false, false, false, true,
false, true,
),
"znver1" | "znver2" | "znver3" | "znver4" | "znver5" => (
true, false, false, false, false, false, true, false, true, true, false, true, false,
true,
),
"bdver1" | "bdver2" | "bdver3" | "bdver4" | "excavator" => (
true, false, false, false, false, false, true, true, true, true, false, true, false,
true,
),
"btver1" | "btver2" => (
true, true, false, false, true, true, true, true, false, false, false, false, false,
false,
),
"k8" | "opteron" | "athlon64" | "amdfam10" | "barcelona" => (
false, false, true, true, true, false, true, false, false, false, false, false, false,
true,
),
"c3" | "c7" | "nano" | "zxc" | "zxd" => (
false, true, true, true, true, true, true, false, false, false, false, false, false,
false,
),
_ => (
false, false, false, false, false, false, false, true, false, false, false, true,
false, true,
),
}
}
fn sched_model_for_cpu(cpu: &str) -> X86SchedModel {
let cpu_lower = cpu.to_lowercase();
match cpu_lower.as_str() {
"pentium4" | "pentium4m" => X86SchedModel::NetBurst,
"core2" | "penryn" => X86SchedModel::Core2,
"nehalem" | "westmere" | "corei7" => X86SchedModel::Nehalem,
"sandybridge" | "corei7-2" | "snb" => X86SchedModel::SandyBridge,
"ivybridge" | "corei7-3" | "ivb" => X86SchedModel::IvyBridge,
"haswell" | "corei7-4" | "hsw" => X86SchedModel::Haswell,
"broadwell" | "corei7-5" | "bdw" => X86SchedModel::Broadwell,
"skylake" | "corei7-6" | "skl" => X86SchedModel::SkylakeClient,
"skylake-avx512" | "skx" => X86SchedModel::SkylakeServer,
"cascadelake" | "cfl" => X86SchedModel::CascadeLake,
"cooperlake" | "cpl" => X86SchedModel::CooperLake,
"cannonlake" | "cnl" => X86SchedModel::CannonLake,
"icelake-client" | "icl" => X86SchedModel::IceLakeClient,
"icelake-server" | "icx" => X86SchedModel::IceLakeServer,
"tigerlake" | "tgl" => X86SchedModel::TigerLake,
"sapphirerapids" | "spr" => X86SchedModel::SapphireRapids,
"emeraldrapids" | "emr" => X86SchedModel::EmeraldRapids,
"graniterapids" | "gnr" => X86SchedModel::GraniteRapids,
"graniterapids-d" | "gnr-d" => X86SchedModel::GraniteRapids,
"alderlake" | "adl" => X86SchedModel::AlderLake,
"rocketlake" | "rkl" => X86SchedModel::RocketLake,
"meteorlake" | "mtl" => X86SchedModel::MeteorLake,
"arrowlake" | "arl" => X86SchedModel::ArrowLake,
"lunarlake" | "lnl" => X86SchedModel::LunarLake,
"atom" | "bonnell" => X86SchedModel::Bonnell,
"silvermont" | "slm" => X86SchedModel::Silvermont,
"goldmont" | "glm" => X86SchedModel::Goldmont,
"goldmont-plus" | "glp" => X86SchedModel::GoldmontPlus,
"tremont" | "tnt" => X86SchedModel::Tremont,
"gracemont" => X86SchedModel::Gracemont,
"knl" | "knightslanding" => X86SchedModel::KnightsLanding,
"knm" | "knightsmill" => X86SchedModel::KnightsLanding,
"k8" | "opteron" | "athlon64" | "athlon-fx" => X86SchedModel::K8,
"amdfam10" | "barcelona" => X86SchedModel::K10,
"btver1" => X86SchedModel::Bobcat,
"btver2" => X86SchedModel::Jaguar,
"bdver1" => X86SchedModel::Bulldozer,
"bdver2" => X86SchedModel::Piledriver,
"bdver3" => X86SchedModel::Steamroller,
"bdver4" | "excavator" | "bdver5" => X86SchedModel::Excavator,
"znver1" => X86SchedModel::Zen1,
"znver2" => X86SchedModel::Zen2,
"znver3" => X86SchedModel::Zen3,
"znver4" => X86SchedModel::Zen4,
"znver5" => X86SchedModel::Zen5,
"pentium" | "pentiumpro" | "pentium2" | "pentium3" | "pentiumiii" => X86SchedModel::P6,
"pentium-m" => X86SchedModel::P6,
"i686" | "i586" | "i486" | "i386" => X86SchedModel::Generic,
"c3" | "c7" | "nano" | "zxc" | "zxd" => X86SchedModel::Generic,
_ => X86SchedModel::Generic,
}
}
fn sched_info_for_model(model: X86SchedModel) -> X86SchedInfo {
match model {
X86SchedModel::SkylakeClient
| X86SchedModel::SkylakeServer
| X86SchedModel::CascadeLake
| X86SchedModel::CooperLake
| X86SchedModel::CannonLake
| X86SchedModel::IceLakeClient
| X86SchedModel::IceLakeServer
| X86SchedModel::TigerLake
| X86SchedModel::RocketLake
| X86SchedModel::AlderLake
| X86SchedModel::MeteorLake => X86SchedInfo {
dispatch: 6,
issue: 8,
retire: 8,
rob_size: 224,
ld_buf: 72,
st_buf: 56,
},
X86SchedModel::Haswell | X86SchedModel::Broadwell => X86SchedInfo {
dispatch: 4,
issue: 8,
retire: 4,
rob_size: 192,
ld_buf: 72,
st_buf: 42,
},
X86SchedModel::SandyBridge | X86SchedModel::IvyBridge => X86SchedInfo {
dispatch: 4,
issue: 6,
retire: 4,
rob_size: 168,
ld_buf: 64,
st_buf: 36,
},
X86SchedModel::Nehalem => X86SchedInfo {
dispatch: 4,
issue: 6,
retire: 4,
rob_size: 128,
ld_buf: 48,
st_buf: 32,
},
X86SchedModel::SapphireRapids | X86SchedModel::EmeraldRapids => X86SchedInfo {
dispatch: 6,
issue: 12,
retire: 8,
rob_size: 512,
ld_buf: 192,
st_buf: 114,
},
X86SchedModel::GraniteRapids => X86SchedInfo {
dispatch: 8,
issue: 12,
retire: 8,
rob_size: 576,
ld_buf: 240,
st_buf: 128,
},
X86SchedModel::ArrowLake | X86SchedModel::LunarLake => X86SchedInfo {
dispatch: 8,
issue: 10,
retire: 8,
rob_size: 448,
ld_buf: 128,
st_buf: 72,
},
X86SchedModel::Bonnell => X86SchedInfo {
dispatch: 2,
issue: 2,
retire: 2,
rob_size: 0,
ld_buf: 8,
st_buf: 4,
},
X86SchedModel::Silvermont | X86SchedModel::Goldmont | X86SchedModel::GoldmontPlus => {
X86SchedInfo {
dispatch: 2,
issue: 3,
retire: 2,
rob_size: 32,
ld_buf: 10,
st_buf: 8,
}
}
X86SchedModel::Tremont | X86SchedModel::Gracemont => X86SchedInfo {
dispatch: 2,
issue: 4,
retire: 4,
rob_size: 208,
ld_buf: 32,
st_buf: 22,
},
X86SchedModel::KnightsLanding => X86SchedInfo {
dispatch: 2,
issue: 2,
retire: 2,
rob_size: 72,
ld_buf: 32,
st_buf: 20,
},
X86SchedModel::Zen1 => X86SchedInfo {
dispatch: 6,
issue: 6,
retire: 8,
rob_size: 192,
ld_buf: 72,
st_buf: 44,
},
X86SchedModel::Zen2 => X86SchedInfo {
dispatch: 6,
issue: 7,
retire: 8,
rob_size: 224,
ld_buf: 84,
st_buf: 48,
},
X86SchedModel::Zen3 => X86SchedInfo {
dispatch: 6,
issue: 8,
retire: 8,
rob_size: 256,
ld_buf: 116,
st_buf: 64,
},
X86SchedModel::Zen4 => X86SchedInfo {
dispatch: 9,
issue: 9,
retire: 9,
rob_size: 320,
ld_buf: 118,
st_buf: 64,
},
X86SchedModel::Zen5 => X86SchedInfo {
dispatch: 10,
issue: 10,
retire: 10,
rob_size: 448,
ld_buf: 144,
st_buf: 88,
},
X86SchedModel::Bulldozer | X86SchedModel::Piledriver => X86SchedInfo {
dispatch: 4,
issue: 4,
retire: 4,
rob_size: 0,
ld_buf: 40,
st_buf: 24,
},
X86SchedModel::Steamroller | X86SchedModel::Excavator => X86SchedInfo {
dispatch: 4,
issue: 4,
retire: 4,
rob_size: 0,
ld_buf: 48,
st_buf: 32,
},
X86SchedModel::Bobcat | X86SchedModel::Jaguar => X86SchedInfo {
dispatch: 2,
issue: 2,
retire: 2,
rob_size: 0,
ld_buf: 8,
st_buf: 6,
},
X86SchedModel::K8 | X86SchedModel::K10 => X86SchedInfo {
dispatch: 3,
issue: 3,
retire: 3,
rob_size: 72,
ld_buf: 32,
st_buf: 20,
},
_ => X86SchedInfo {
dispatch: 1,
issue: 1,
retire: 1,
rob_size: 0,
ld_buf: 4,
st_buf: 4,
},
}
}
pub fn apply_feature_dependencies(features: &mut HashSet<String>) {
if features.contains("sse4.2") {
features.insert("sse4.1".to_string());
}
if features.contains("sse4.1") {
features.insert("ssse3".to_string());
}
if features.contains("ssse3") {
features.insert("sse3".to_string());
}
if features.contains("sse3") {
features.insert("sse2".to_string());
}
if features.contains("sse2") {
features.insert("sse".to_string());
}
if features.contains("avx2") {
features.insert("avx".to_string());
}
if features.contains("avx") {
features.insert("sse4.2".to_string());
}
if features.contains("avx512vl") {
features.insert("avx512f".to_string());
}
if features.contains("avx512bw") {
features.insert("avx512f".to_string());
}
if features.contains("avx512dq") {
features.insert("avx512f".to_string());
}
if features.contains("fma") {
features.insert("avx".to_string());
}
if features.contains("f16c") {
features.insert("avx".to_string());
}
if features.contains("xsavec") || features.contains("xsaves") || features.contains("xsaveopt") {
features.insert("xsave".to_string());
}
if features.contains("amx-tile")
|| features.contains("amx-bf16")
|| features.contains("amx-int8")
|| features.contains("amx-fp16")
{
features.insert("avx512f".to_string());
}
if features.contains("sha") {
features.insert("sse2".to_string());
}
if features.contains("xop") || features.contains("fma4") {
features.insert("avx".to_string());
}
if features.contains("bmi2") {
features.insert("bmi".to_string());
}
if features.contains("cet") {
features.insert("sse2".to_string());
}
}
pub fn feature_dependency_chains() -> Vec<(&'static str, Vec<&'static str>)> {
vec![
("sse4.2", vec!["sse4.1"]),
("sse4.1", vec!["ssse3"]),
("ssse3", vec!["sse3"]),
("sse3", vec!["sse2"]),
("sse2", vec!["sse"]),
("avx2", vec!["avx"]),
("avx", vec!["sse4.2"]),
("avx512vl", vec!["avx512f"]),
("avx512bw", vec!["avx512f"]),
("avx512dq", vec!["avx512f"]),
("fma", vec!["avx"]),
("f16c", vec!["avx"]),
("xsavec", vec!["xsave"]),
("xsaves", vec!["xsave"]),
("xsaveopt", vec!["xsave"]),
("amx-tile", vec!["avx512f"]),
("amx-bf16", vec!["avx512f"]),
("amx-int8", vec!["avx512f"]),
("amx-fp16", vec!["avx512f"]),
("sha", vec!["sse2"]),
("xop", vec!["avx"]),
("fma4", vec!["avx"]),
("bmi2", vec!["bmi"]),
("cet", vec!["sse2"]),
]
}
pub fn features_for_cpu(cpu: &str) -> HashSet<String> {
let cpu_lower = cpu.to_lowercase();
let features: &[&str] = match cpu_lower.as_str() {
"generic" => &[
"cmov", "mmx", "sse", "sse2", "fxr", "nopl", "xsave", "xsaveopt",
],
"x86-64-v1" => &[
"cmov", "mmx", "sse", "sse2", "fxr", "nopl", "xsave", "xsaveopt",
],
"x86-64-v2" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"lahf_sahf",
"fxr",
"nopl",
"xsave",
"xsaveopt",
],
"x86-64-v3" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"lahf_sahf",
"avx",
"avx2",
"bmi",
"bmi2",
"fma",
"f16c",
"lzcnt",
"movbe",
"xsavec",
"fxr",
"nopl",
"xsave",
"xsaveopt",
],
"x86-64-v4" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"lahf_sahf",
"avx",
"avx2",
"bmi",
"bmi2",
"fma",
"f16c",
"lzcnt",
"movbe",
"xsavec",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"fxr",
"nopl",
"xsave",
"xsaveopt",
],
"pentium4" | "pentium4m" => &["cmov", "mmx", "sse", "sse2", "fxr", "nopl"],
"core2" | "penryn" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "fxr", "nopl", "xsave", "xsaveopt",
],
"nehalem" | "corei7" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "fxr",
"nopl", "xsave", "xsaveopt",
],
"westmere" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "fxr",
"nopl", "xsave", "xsaveopt",
],
"sandybridge" | "corei7-2" | "snb" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"xsave", "xsaveopt", "fxr", "nopl",
],
"ivybridge" | "corei7-3" | "ivb" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"f16c", "rdrnd", "xsave", "xsaveopt", "fxr", "nopl",
],
"haswell" | "corei7-4" | "hsw" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "xsave", "xsaveopt",
"xsavec", "fxr", "nopl",
],
"broadwell" | "corei7-5" | "bdw" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"rtm", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"skylake" | "corei7-6" | "skl" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"rtm", "sgx", "xsave", "xsaveopt", "xsavec", "xsaves", "fxr", "nopl",
],
"skylake-avx512" | "skx" | "corei7-6-avx512" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"rtm", "avx512f", "avx512bw", "avx512dq", "avx512vl", "xsave", "xsaveopt", "xsavec",
"xsaves", "fxr", "nopl",
],
"cannonlake" | "cnl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"cascadelake" | "cfl" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"rtm", "avx512f", "avx512bw", "avx512dq", "avx512vl", "xsave", "xsaveopt", "xsavec",
"xsaves", "fxr", "nopl",
],
"cooperlake" | "cpl" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"rtm", "avx512f", "avx512bw", "avx512dq", "avx512vl", "xsave", "xsaveopt", "xsavec",
"xsaves", "fxr", "nopl",
],
"icelake-client" | "icl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"icelake-server" | "icx" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"alderlake" | "adl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"rocketlake" | "rkl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"atom" | "bonnell" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "movbe", "fxr", "nopl", "xsave",
"xsaveopt",
],
"silvermont" | "slm" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "movbe",
"rdrnd", "fxr", "nopl", "xsave", "xsaveopt",
],
"goldmont" | "glm" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "movbe",
"rdrnd", "rdseed", "sha", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"goldmont-plus" | "glp" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "movbe",
"rdrnd", "rdseed", "sha", "sgx", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"tremont" | "tnt" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "movbe",
"rdrnd", "rdseed", "sha", "gfni", "clwb", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"knl" | "knightslanding" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "avx512f", "rdrnd", "rdseed",
"adx", "rtm", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"knm" | "knightsmill" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "avx512f", "rdrnd", "rdseed",
"adx", "rtm", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"znver1" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"clzero", "mwaitx", "sha", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"znver2" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"avx2", "fma", "f16c", "bmi", "bmi2", "lzcnt", "movbe", "rdrnd", "rdseed", "adx",
"clzero", "mwaitx", "clwb", "sha", "xsave", "xsaveopt", "xsavec", "fxr", "nopl",
],
"znver3" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"clzero",
"mwaitx",
"clwb",
"pku",
"vaes",
"vpclmulqdq",
"sha",
"xsave",
"xsaveopt",
"xsavec",
"fxr",
"nopl",
],
"znver4" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"clzero",
"mwaitx",
"clwb",
"pku",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"vaes",
"vpclmulqdq",
"gfni",
"sha",
"xsave",
"xsaveopt",
"xsavec",
"fxr",
"nopl",
],
"i386" => &["x87", "nopl"],
"i486" => &["x87", "nopl"],
"i586" | "pentium" => &["x87", "nopl"],
"i686" | "pentiumpro" | "pentium2" => &["x87", "cmov", "mmx", "nopl"],
"pentium3" | "pentiumiii" => &["x87", "cmov", "mmx", "sse", "nopl"],
"pentium-m" => &["x87", "cmov", "mmx", "sse", "sse2", "nopl"],
"k6" => &["x87", "mmx", "nopl"],
"k6-2" => &["x87", "mmx", "3dnow", "nopl"],
"k6-3" => &["x87", "mmx", "3dnow", "nopl"],
"athlon" | "athlon-xp" | "athlon-mp" => &["x87", "mmx", "3dnow", "sse", "nopl"],
"athlon-4" => &["x87", "mmx", "3dnow", "sse", "sse2", "nopl"],
"k8" | "opteron" | "athlon64" | "athlon-fx" => {
&["x87", "cmov", "mmx", "sse", "sse2", "3dnow", "fxr", "nopl"]
}
"k8-sse3" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "3dnow", "fxr", "nopl",
],
"amdfam10" | "barcelona" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "popcnt", "fxr",
"nopl", "xsave", "xsaveopt",
],
"btver1" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "f16c", "movbe", "lzcnt", "prfchw", "xsave", "xsaveopt", "fxr", "nopl",
],
"btver2" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "f16c", "bmi", "bmi2", "fma", "movbe", "lzcnt", "prfchw", "rdrnd", "xsave",
"xsaveopt", "fxr", "nopl",
],
"bdver1" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "f16c", "bmi", "lzcnt", "prfchw", "xsave", "xsaveopt", "fxr", "nopl",
],
"bdver2" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "f16c", "bmi", "bmi2", "fma", "lzcnt", "prfchw", "xsave", "xsaveopt", "fxr",
"nopl",
],
"bdver3" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "avx2", "f16c", "bmi", "bmi2", "fma", "lzcnt", "movbe", "prfchw", "xsave",
"xsaveopt", "fxr", "nopl",
],
"bdver4" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "avx2", "f16c", "bmi", "bmi2", "fma", "lzcnt", "movbe", "mwaitx", "rdrnd",
"xsave", "xsaveopt", "fxr", "nopl",
],
"excavator" | "bdver5" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "avx2", "f16c", "bmi", "bmi2", "fma", "lzcnt", "movbe", "mwaitx", "rdrnd",
"xsave", "xsaveopt", "fxr", "nopl",
],
"znver5" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"clzero",
"mwaitx",
"clwb",
"pku",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"vaes",
"vpclmulqdq",
"gfni",
"sha",
"avx-vnni",
"avx-ifma",
"avx-ne-convert",
"avx-vnni-int8",
"prefetchiti",
"xsave",
"xsaveopt",
"xsavec",
"fxr",
"nopl",
],
"tigerlake" | "tgl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"avx-vnni",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"sapphirerapids" | "spr" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"avx-vnni",
"avx-ifma",
"avx-vnni-int8",
"amx-tile",
"amx-bf16",
"amx-int8",
"amx-fp16",
"serialize",
"tsxldtrk",
"cldemote",
"waitpkg",
"enqcmd",
"movdiri",
"movdir64b",
"pku",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"emeraldrapids" | "emr" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"avx-vnni",
"avx-ifma",
"avx-vnni-int8",
"amx-tile",
"amx-bf16",
"amx-int8",
"amx-fp16",
"cmpccxadd",
"avx-ne-convert",
"prefetchiti",
"rao-int",
"serialize",
"tsxldtrk",
"cldemote",
"waitpkg",
"enqcmd",
"movdiri",
"movdir64b",
"pku",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"graniterapids" | "gnr" | "graniterapids-d" | "gnr-d" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"avx512f",
"avx512bw",
"avx512dq",
"avx512vl",
"avx-vnni",
"avx-ifma",
"avx-vnni-int8",
"amx-tile",
"amx-bf16",
"amx-int8",
"amx-fp16",
"cmpccxadd",
"avx-ne-convert",
"prefetchiti",
"rao-int",
"sha512",
"sm3",
"sm4",
"serialize",
"tsxldtrk",
"cldemote",
"waitpkg",
"enqcmd",
"movdiri",
"movdir64b",
"pku",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"meteorlake" | "mtl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"rtm",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"arrowlake" | "arl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"avx-vnni",
"avx-ifma",
"avx-ne-convert",
"avx-vnni-int8",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"lunarlake" | "lnl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"avx-vnni",
"avx-ifma",
"avx-ne-convert",
"avx-vnni-int8",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"pantherlake" | "ptl" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"avx-vnni",
"avx-ifma",
"avx-ne-convert",
"avx-vnni-int8",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"alderlake-n" | "adl-n" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"cet",
"xsave",
"xsaveopt",
"xsavec",
"xsaves",
"fxr",
"nopl",
],
"gracemont" => &[
"cmov",
"mmx",
"sse",
"sse2",
"sse3",
"ssse3",
"sse4.1",
"sse4.2",
"popcnt",
"avx",
"avx2",
"fma",
"f16c",
"bmi",
"bmi2",
"lzcnt",
"movbe",
"rdrnd",
"rdseed",
"adx",
"sha",
"gfni",
"vaes",
"vpclmulqdq",
"cet",
"waitpkg",
"cldemote",
"serialize",
"xsave",
"xsaveopt",
"xsavec",
"fxr",
"nopl",
],
"c3" | "c3-2" => &["x87", "cmov", "mmx", "sse", "nopl"],
"c7" => &["x87", "cmov", "mmx", "sse", "sse2", "sse3", "nopl"],
"nano" | "nano-3000" | "nano-x2" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "nopl",
],
"zxc" | "zhangjiang" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"nopl",
],
"zxd" | "wudaokou" => &[
"x87", "cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt",
"avx", "f16c", "nopl",
],
"larrabee" => &[
"cmov", "mmx", "sse", "sse2", "sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx",
"xsave", "xsaveopt", "fxr", "nopl",
],
_ => &[
"cmov", "mmx", "sse", "sse2", "fxr", "nopl", "xsave", "xsaveopt",
],
};
features.iter().map(|s| s.to_string()).collect()
}
pub fn parse_feature_string(features: &mut HashSet<String>, feature_str: &str) {
if feature_str.is_empty() {
return;
}
for token in feature_str.split(',') {
let token = token.trim();
if token.is_empty() {
continue;
}
let (action, name) = if let Some(rest) = token.strip_prefix('+') {
(true, rest.trim().to_lowercase())
} else if let Some(rest) = token.strip_prefix('-') {
(false, rest.trim().to_lowercase())
} else {
(true, token.to_lowercase())
};
let name = normalise_feature_name(&name);
if action {
features.insert(name.to_string());
} else {
features.remove(name);
}
}
}
fn normalise_feature_name(name: &str) -> &str {
match name {
"sse4.1" | "sse4_1" | "sse41" => "sse4.1",
"sse4.2" | "sse4_2" | "sse42" => "sse4.2",
"avx512f" | "avx-512f" => "avx512f",
"avx512bw" | "avx-512bw" => "avx512bw",
"avx512dq" | "avx-512dq" => "avx512dq",
"avx512vl" | "avx-512vl" => "avx512vl",
"vpclmulqdq" | "vpclmul" => "vpclmulqdq",
"lahf_sahf" | "sahf_lahf" => "lahf_sahf",
other => other,
}
}
fn triple_is_64_bit(triple: &str) -> bool {
let triple_lower = triple.to_lowercase();
if triple_lower.starts_with("x86-64") {
return true;
}
let arch = triple_lower.split('-').next().unwrap_or("");
matches!(arch, "x86_64" | "amd64")
}
fn default_inline_threshold(cpu: &str) -> u32 {
let cpu_lower = cpu.to_lowercase();
match cpu_lower.as_str() {
"haswell" | "broadwell" | "skylake" | "skylake-avx512" | "cannonlake" | "cascadelake"
| "icelake-client" | "icelake-server" | "rocketlake" | "znver1" | "znver2" | "znver3"
| "znver4" => 250,
"sandybridge" | "ivybridge" | "nehalem" | "westmere" | "core2" | "penryn" | "bdver1"
| "bdver2" | "bdver3" | "bdver4" | "excavator" => 200,
"atom" | "silvermont" | "goldmont" | "goldmont-plus" | "tremont" | "btver1" | "btver2" => {
150
}
_ => 180,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detect_64bit_triple() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(st.is_64_bit);
assert!(st.in_64bit_mode());
assert!(!st.in_32bit_mode());
}
#[test]
fn test_detect_32bit_triple() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "generic", "");
assert!(!st.is_64_bit);
assert!(!st.in_64bit_mode());
assert!(st.in_32bit_mode());
}
#[test]
fn test_detect_amd64_triple() {
let st = X86Subtarget::new("amd64-unknown-freebsd", "generic", "");
assert!(st.is_64_bit);
}
#[test]
fn test_generic_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(st.has_sse2());
assert!(st.has_cmov());
assert!(st.has_mmx());
assert!(!st.has_avx());
assert!(!st.has_avx2());
}
#[test]
fn test_nehalem_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "nehalem", "");
assert!(st.has_sse2());
assert!(st.has_sse3());
assert!(st.has_ssse3());
assert!(st.has_sse41());
assert!(st.has_sse42());
assert!(st.has_popcnt());
assert!(!st.has_avx());
}
#[test]
fn test_haswell_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "haswell", "");
assert!(st.has_sse2());
assert!(st.has_avx());
assert!(st.has_avx2());
assert!(st.has_fma());
assert!(st.has_f16c());
assert!(st.has_bmi());
assert!(st.has_bmi2());
assert!(st.has_lzcnt());
assert!(st.has_movbe());
assert!(st.has_rdrnd());
assert!(!st.has_avx512f());
}
#[test]
fn test_skylake_avx512_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skylake-avx512", "");
assert!(st.has_avx2());
assert!(st.has_avx512f());
assert!(st.has_avx512bw());
assert!(st.has_avx512dq());
assert!(st.has_avx512vl());
assert!(st.has_avx512());
}
#[test]
fn test_znver3_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver3", "");
assert!(st.has_avx2());
assert!(st.has_vaes());
assert!(st.has_vpclmulqdq());
assert!(st.has_clzero());
assert!(st.has_mwaitx());
assert!(st.has_pku());
assert!(st.has_sha());
assert!(!st.has_avx512f());
}
#[test]
fn test_znver4_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver4", "");
assert!(st.has_avx2());
assert!(st.has_avx512f());
assert!(st.has_avx512bw());
assert!(st.has_avx512dq());
assert!(st.has_avx512vl());
assert!(st.has_gfni());
assert!(st.has_vaes());
}
#[test]
fn test_knl_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "knl", "");
assert!(st.has_avx512f());
assert!(!st.has_avx512bw());
assert!(!st.has_avx512dq());
assert!(!st.has_avx512vl());
}
#[test]
fn test_atom_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "atom", "");
assert!(st.has_sse3());
assert!(st.has_ssse3());
assert!(!st.has_sse41());
assert!(!st.has_avx());
assert!(st.has_movbe());
}
#[test]
fn test_silvermont_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "silvermont", "");
assert!(st.has_sse41());
assert!(st.has_sse42());
assert!(st.has_popcnt());
assert!(!st.has_avx());
}
#[test]
fn test_tremont_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "tremont", "");
assert!(st.has_sse42());
assert!(st.has_sha());
assert!(st.has_gfni());
assert!(st.has_clwb());
assert!(!st.has_avx());
}
#[test]
fn test_i386_baseline() {
let st = X86Subtarget::new("i386-unknown-linux-gnu", "i386", "");
assert!(st.has_x87());
assert!(!st.has_cmov());
assert!(!st.has_mmx());
assert!(!st.has_sse());
assert!(!st.has_sse2());
}
#[test]
fn test_i686_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "i686", "");
assert!(st.has_cmov());
assert!(st.has_mmx());
assert!(!st.has_sse());
}
#[test]
fn test_pentium4_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "pentium4", "");
assert!(st.has_sse2());
assert!(!st.has_sse3());
}
#[test]
fn test_core2_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "core2", "");
assert!(st.has_sse3());
assert!(st.has_ssse3());
assert!(!st.has_sse41());
}
#[test]
fn test_x86_64_v1() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "x86-64-v1", "");
assert!(st.has_sse2());
assert!(!st.has_sse3());
assert!(!st.has_avx());
}
#[test]
fn test_x86_64_v2() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "x86-64-v2", "");
assert!(st.has_sse42());
assert!(st.has_popcnt());
assert!(!st.has_avx());
}
#[test]
fn test_x86_64_v3() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "x86-64-v3", "");
assert!(st.has_avx2());
assert!(st.has_bmi());
assert!(st.has_fma());
assert!(!st.has_avx512f());
}
#[test]
fn test_x86_64_v4() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "x86-64-v4", "");
assert!(st.has_avx512f());
assert!(st.has_avx512bw());
assert!(st.has_avx512dq());
assert!(st.has_avx512vl());
}
#[test]
fn test_feature_string_enable() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+avx,+fma");
assert!(st.has_avx());
assert!(st.has_fma());
assert!(st.has_sse2()); }
#[test]
fn test_feature_string_disable() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "haswell", "-avx,-avx2");
assert!(!st.has_avx());
assert!(!st.has_avx2());
assert!(st.has_sse2()); }
#[test]
fn test_feature_string_mixed() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "nehalem", "+avx,-popcnt,+rdrnd");
assert!(st.has_avx());
assert!(!st.has_popcnt());
assert!(st.has_rdrnd());
assert!(st.has_sse42()); }
#[test]
fn test_feature_string_bare_names() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "avx,bmi");
assert!(st.has_avx());
assert!(st.has_bmi());
}
#[test]
fn test_feature_string_empty() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(st.has_sse2());
}
#[test]
fn test_feature_string_alias_sse41() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+sse41,+sse42");
assert!(st.has_sse41());
assert!(st.has_sse42());
}
#[test]
fn test_feature_string_whitespace() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", " +avx , -sse2 ");
assert!(st.has_avx());
assert!(!st.has_sse2());
}
#[test]
fn test_stack_alignment_64bit() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert_eq!(st.get_stack_alignment(), 16);
}
#[test]
fn test_stack_alignment_32bit_no_avx() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "generic", "");
assert_eq!(st.get_stack_alignment(), 4);
}
#[test]
fn test_stack_alignment_32bit_with_avx() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "generic", "+avx");
assert_eq!(st.get_stack_alignment(), 16);
}
#[test]
fn test_vector_width_none() {
let st = X86Subtarget::new("i386-unknown-linux-gnu", "i386", "");
assert_eq!(st.get_pref_vector_width(), 0);
}
#[test]
fn test_vector_width_sse2() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert_eq!(st.get_pref_vector_width(), 128);
}
#[test]
fn test_vector_width_avx() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "sandybridge", "");
assert_eq!(st.get_pref_vector_width(), 256);
}
#[test]
fn test_vector_width_avx512() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skylake-avx512", "");
assert_eq!(st.get_pref_vector_width(), 512);
}
#[test]
fn test_inline_threshold_haswell() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "haswell", "");
assert_eq!(st.get_max_inline_size_threshold(), 250);
}
#[test]
fn test_inline_threshold_atom() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "atom", "");
assert_eq!(st.get_max_inline_size_threshold(), 150);
}
#[test]
fn test_inline_threshold_nehalem() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "nehalem", "");
assert_eq!(st.get_max_inline_size_threshold(), 200);
}
#[test]
fn test_soft_float_default() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(!st.use_soft_float());
}
#[test]
fn test_has_feature() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "haswell", "");
assert!(st.has_feature("avx2"));
assert!(!st.has_feature("avx512f"));
}
#[test]
fn test_get_feature_set() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
let fs = st.get_feature_set();
assert!(fs.contains("sse2"));
assert!(fs.contains("cmov"));
}
#[test]
fn test_feature_string_output() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
let s = st.feature_string();
assert!(s.contains("sse2"));
assert!(s.contains("cmov"));
}
#[test]
fn test_unknown_cpu_fallback() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "madeup-cpu-name", "");
assert!(st.has_sse2());
assert!(st.has_cmov());
assert!(!st.has_avx());
}
#[test]
fn test_cpu_alias_snb() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "snb", "");
assert!(st.has_avx());
assert!(!st.has_avx2());
}
#[test]
fn test_cpu_alias_skx() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skx", "");
assert!(st.has_avx512f());
}
#[test]
fn test_amd_znver1_clzero() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver1", "");
assert!(st.has_feature("clzero"));
assert!(st.has_feature("mwaitx"));
assert!(!st.has_clwb()); }
#[test]
fn test_amd_znver2_clwb() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver2", "");
assert!(st.has_clwb());
assert!(!st.has_pku()); }
#[test]
fn test_bdver4_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "bdver4", "");
assert!(st.has_avx2());
assert!(st.has_mwaitx());
assert!(!st.has_avx512f());
}
#[test]
fn test_lahf_sahf() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "x86-64-v2", "");
assert!(st.has_lahf_sahf);
assert!(st.has_feature("lahf_sahf"));
}
#[test]
fn test_feature_alias_lahf_sahf() {
let mut fs = HashSet::new();
parse_feature_string(&mut fs, "+sahf_lahf");
assert!(fs.contains("lahf_sahf"));
}
#[test]
fn test_cannonlake_security_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "cannonlake", "");
assert!(st.has_sha());
assert!(st.has_gfni());
assert!(st.has_vaes());
assert!(st.has_vpclmulqdq());
}
#[test]
fn test_alderlake_cet() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "alderlake", "");
assert!(st.has_cet());
assert!(st.has_sha());
}
#[test]
fn test_parse_feature_comma_only() {
let mut fs = HashSet::new();
parse_feature_string(&mut fs, ",,,");
assert!(fs.is_empty());
}
#[test]
fn test_parse_feature_unknown_ignored() {
let mut fs = HashSet::new();
fs.insert("sse2".to_string());
parse_feature_string(&mut fs, "+bogus-feature");
assert!(fs.contains("bogus-feature"));
}
#[test]
fn test_parse_feature_leading_trailing_spaces() {
let mut fs = HashSet::new();
parse_feature_string(&mut fs, " +avx , -mmx ");
assert!(fs.contains("avx"));
assert!(!fs.contains("mmx"));
}
#[test]
fn test_triple_is_64_bit_various() {
assert!(triple_is_64_bit("x86_64-unknown-linux-gnu"));
assert!(triple_is_64_bit("AMD64-pc-windows-msvc"));
assert!(triple_is_64_bit("x86-64-apple-darwin"));
assert!(!triple_is_64_bit("i686-pc-linux-gnu"));
assert!(!triple_is_64_bit("i386-unknown-freebsd"));
assert!(!triple_is_64_bit("x86-pc-windows"));
}
#[test]
fn test_has_feature_negative() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(!st.has_feature("avx512f"));
assert!(!st.has_feature("nonexistent"));
}
#[test]
fn test_inline_threshold_unknown_cpu() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "some-future-cpu", "");
assert_eq!(st.get_max_inline_size_threshold(), 180);
}
#[test]
fn test_feature_string_default_64bit_sse2() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "-sse2");
assert!(!st.has_sse2());
let st2 = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "");
assert!(st2.has_sse2());
}
#[test]
fn test_default_64bit_cmov() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "i386", "");
assert!(st.has_cmov());
}
#[test]
fn test_sapphirerapids_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "sapphirerapids", "");
assert!(st.has_avx512f());
assert!(st.has_amx_tile);
assert!(st.has_amx_bf16);
assert!(st.has_amx_int8);
assert!(st.has_amx_fp16);
assert!(st.has_serialize);
assert!(st.has_tsxldtrk);
assert!(st.has_enqcmd);
assert!(st.has_movdiri);
assert!(st.has_movdir64b);
}
#[test]
fn test_emeraldrapids_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "emeraldrapids", "");
assert!(st.has_avx512f());
assert!(st.has_amx_tile);
assert!(st.has_cmpccxadd);
assert!(st.has_avx_ne_convert);
assert!(st.has_prefetchiti);
assert!(st.has_raoint);
}
#[test]
fn test_graniterapids_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "graniterapids", "");
assert!(st.has_avx512f());
assert!(st.has_amx_tile);
assert!(st.has_sha512);
assert!(st.has_sm3);
assert!(st.has_sm4);
assert!(st.has_cmpccxadd);
assert!(st.has_prefetchiti);
}
#[test]
fn test_graniterapids_d_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "graniterapids-d", "");
assert!(st.has_avx512f());
assert!(st.has_sha512);
assert!(st.has_sm3);
assert!(st.has_sm4);
}
#[test]
fn test_znver5_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver5", "");
assert!(st.has_avx512f());
assert!(st.has_avx512bw());
assert!(st.has_avx512dq());
assert!(st.has_avx512vl());
assert!(st.has_avx_vnni);
assert!(st.has_avx_ifma);
assert!(st.has_avx_ne_convert);
assert!(st.has_avx_vnni_int8);
assert!(st.has_prefetchiti);
assert!(st.has_gfni());
assert!(st.has_vaes());
assert!(st.has_clwb());
assert!(st.has_pku);
}
#[test]
fn test_tigerlake_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "tigerlake", "");
assert!(st.has_avx512f());
assert!(st.has_avx512bw());
assert!(st.has_avx512dq());
assert!(st.has_avx512vl());
assert!(st.has_avx_vnni);
assert!(st.has_sha());
assert!(st.has_gfni());
assert!(st.has_vaes());
}
#[test]
fn test_alderlake_n_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "alderlake-n", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(!st.has_rtm);
assert!(st.has_sha());
assert!(st.has_cet);
}
#[test]
fn test_via_c3_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "c3", "");
assert!(st.has_sse());
assert!(!st.has_sse2());
assert!(st.has_cmov());
assert!(st.has_mmx());
}
#[test]
fn test_via_c7_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "c7", "");
assert!(st.has_sse2());
assert!(st.has_sse3());
assert!(!st.has_ssse3());
}
#[test]
fn test_via_nano_features() {
let st = X86Subtarget::new("i686-pc-linux-gnu", "nano", "");
assert!(st.has_ssse3());
assert!(st.has_sse41());
assert!(!st.has_sse42());
}
#[test]
fn test_zhaoxin_zxc_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "zxc", "");
assert!(st.has_sse42());
assert!(st.has_popcnt());
assert!(!st.has_avx());
}
#[test]
fn test_zhaoxin_zxd_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "zxd", "");
assert!(st.has_avx());
assert!(st.has_f16c());
assert!(!st.has_avx2());
}
#[test]
fn test_extended_feature_flags_skx() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skx", "");
assert!(st.has_avx512f());
assert!(!st.has_amx_tile);
assert!(!st.has_sha512);
assert!(!st.has_sm3);
assert!(!st.has_sm4);
assert!(!st.has_cet);
}
#[test]
fn test_feature_enable_aes_pclmul() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+aes,+pclmul");
assert!(st.has_aes);
assert!(st.has_pclmul);
}
#[test]
fn test_feature_enable_fsgsbase() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+fsgsbase");
assert!(st.has_fsgsbase);
}
#[test]
fn test_feature_enable_smap_smep() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+smap,+smep");
assert!(st.has_smap);
assert!(st.has_smep);
}
#[test]
fn test_feature_enable_invpcid() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+invpcid");
assert!(st.has_invpcid);
}
#[test]
fn test_feature_enable_xop_fma4() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "generic", "+avx,+xop,+fma4");
assert!(st.has_avx());
assert!(st.has_xop);
assert!(st.has_fma4);
}
#[test]
fn test_tuning_skylake_uses_cmov() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skylake", "");
assert!(st.use_cmov_branch);
assert!(!st.slow_divide_32);
assert!(!st.slow_divide_64);
assert!(st.use_inc_dec);
}
#[test]
fn test_tuning_nehalem_slow_div() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "nehalem", "");
assert!(st.slow_divide_32);
assert!(st.slow_divide_64);
assert!(st.lea_uses_ag);
}
#[test]
fn test_tuning_core2_slow_unaligned() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "core2", "");
assert!(st.slow_unaligned_mem_16);
assert!(st.slow_unaligned_mem_32);
}
#[test]
fn test_tuning_znver3_sqrt_recip_est() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver3", "");
assert!(st.use_sqrt_estimate);
assert!(st.use_reciprocal_estimate);
assert!(st.pad_short_functions);
assert!(st.lea_uses_ag);
}
#[test]
fn test_tuning_znver5_sqrt_recip_est() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver5", "");
assert!(st.use_sqrt_estimate);
assert!(st.use_reciprocal_estimate);
assert!(st.pad_short_functions);
}
#[test]
fn test_tuning_atom_opt_for_size() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "atom", "");
assert!(st.opt_for_size);
assert!(!st.use_cmov_branch);
}
#[test]
fn test_sched_skylake_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "skylake", "");
assert_eq!(st.dispatch_width, 6);
assert_eq!(st.issue_width, 8);
assert_eq!(st.retire_width, 8);
assert_eq!(st.reorder_buffer_size, 224);
}
#[test]
fn test_sched_haswell_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "haswell", "");
assert_eq!(st.dispatch_width, 4);
assert_eq!(st.issue_width, 8);
assert_eq!(st.retire_width, 4);
assert_eq!(st.reorder_buffer_size, 192);
}
#[test]
fn test_sched_sapphirerapids_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "sapphirerapids", "");
assert_eq!(st.dispatch_width, 6);
assert_eq!(st.issue_width, 12);
assert_eq!(st.reorder_buffer_size, 512);
}
#[test]
fn test_sched_graniterapids_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "graniterapids", "");
assert_eq!(st.dispatch_width, 8);
assert_eq!(st.issue_width, 12);
assert_eq!(st.reorder_buffer_size, 576);
}
#[test]
fn test_sched_znver1_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver1", "");
assert_eq!(st.dispatch_width, 6);
assert_eq!(st.retire_width, 8);
assert_eq!(st.reorder_buffer_size, 192);
}
#[test]
fn test_sched_znver4_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver4", "");
assert_eq!(st.dispatch_width, 9);
assert_eq!(st.retire_width, 9);
assert_eq!(st.reorder_buffer_size, 320);
}
#[test]
fn test_sched_znver5_dispatch_width() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "znver5", "");
assert_eq!(st.dispatch_width, 10);
assert_eq!(st.retire_width, 10);
assert_eq!(st.reorder_buffer_size, 448);
}
#[test]
fn test_sched_atom_small() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "atom", "");
assert_eq!(st.dispatch_width, 2);
assert_eq!(st.issue_width, 2);
assert_eq!(st.reorder_buffer_size, 0); }
#[test]
fn test_sched_tremont_rob() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "tremont", "");
assert_eq!(st.dispatch_width, 2);
assert_eq!(st.issue_width, 4);
assert_eq!(st.reorder_buffer_size, 208);
}
#[test]
fn test_feature_dep_avx2_implies_avx() {
let mut fs = HashSet::new();
fs.insert("avx2".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx"));
assert!(fs.contains("sse4.2"));
assert!(fs.contains("sse"));
}
#[test]
fn test_feature_dep_avx512bw_implies_f() {
let mut fs = HashSet::new();
fs.insert("avx512bw".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx512f"));
}
#[test]
fn test_feature_dep_avx512vl_implies_f() {
let mut fs = HashSet::new();
fs.insert("avx512vl".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx512f"));
}
#[test]
fn test_feature_dep_fma_implies_avx() {
let mut fs = HashSet::new();
fs.insert("fma".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx"));
}
#[test]
fn test_feature_dep_amx_tile_implies_avx512f() {
let mut fs = HashSet::new();
fs.insert("amx-tile".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx512f"));
}
#[test]
fn test_feature_dep_bmi2_implies_bmi() {
let mut fs = HashSet::new();
fs.insert("bmi2".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("bmi"));
}
#[test]
fn test_feature_dep_xop_implies_avx() {
let mut fs = HashSet::new();
fs.insert("xop".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx"));
}
#[test]
fn test_feature_dep_fma4_implies_avx() {
let mut fs = HashSet::new();
fs.insert("fma4".to_string());
apply_feature_dependencies(&mut fs);
assert!(fs.contains("avx"));
}
#[test]
fn test_feature_dep_chains_len() {
let chains = feature_dependency_chains();
assert!(!chains.is_empty());
let sse42_chain = chains.iter().find(|(k, _)| *k == "sse4.2");
assert!(sse42_chain.is_some());
assert_eq!(sse42_chain.unwrap().1, vec!["sse4.1"]);
}
#[test]
fn test_sched_model_names() {
assert_eq!(X86SchedModel::SkylakeClient.name(), "SkylakeClient");
assert_eq!(X86SchedModel::Haswell.name(), "Haswell");
assert_eq!(X86SchedModel::Zen1.name(), "Zen1");
assert_eq!(X86SchedModel::Zen5.name(), "Zen5");
assert_eq!(X86SchedModel::SapphireRapids.name(), "SapphireRapids");
assert_eq!(X86SchedModel::GraniteRapids.name(), "GraniteRapids");
assert_eq!(X86SchedModel::Generic.name(), "Generic");
}
#[test]
fn test_sched_info_generic() {
let info = sched_info_for_model(X86SchedModel::Generic);
assert_eq!(info.dispatch, 1);
assert_eq!(info.issue, 1);
assert_eq!(info.retire, 1);
}
#[test]
fn test_sched_info_zen4() {
let info = sched_info_for_model(X86SchedModel::Zen4);
assert_eq!(info.dispatch, 9);
assert_eq!(info.rob_size, 320);
}
#[test]
fn test_meteorlake_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "meteorlake", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(st.has_sha());
assert!(st.has_cet);
}
#[test]
fn test_arrowlake_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "arrowlake", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(st.has_avx_vnni);
assert!(st.has_avx_ifma);
assert!(st.has_avx_ne_convert);
}
#[test]
fn test_lunarlake_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "lunarlake", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(st.has_avx_vnni);
assert!(st.has_cet);
}
#[test]
fn test_pantherlake_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "pantherlake", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(st.has_avx_vnni);
assert!(st.has_cet);
}
#[test]
fn test_gracemont_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "gracemont", "");
assert!(st.has_avx2());
assert!(!st.has_avx512f());
assert!(st.has_waitpkg);
assert!(st.has_cldemote);
assert!(st.has_serialize);
assert!(st.has_cet);
}
#[test]
fn test_larrabee_features() {
let st = X86Subtarget::new("x86_64-unknown-linux-gnu", "larrabee", "");
assert!(st.has_avx());
assert!(!st.has_avx2());
assert!(st.has_sse42());
}
}