use std::collections::HashSet;
const KNOWN_CPUS: &[(&str, &[&str])] = &[
("generic-rv32", &["i"]),
("generic-rv64", &["i"]),
("sifive-e20", &["i", "m", "c"]),
("sifive-e24", &["i", "m", "c"]),
("sifive-e31", &["i", "m", "a", "c"]),
("sifive-e34", &["i", "m", "a", "c"]),
("sifive-e76", &["i", "m", "a", "f", "d", "c"]),
("sifive-s21", &["i", "m", "a", "c"]),
("sifive-s51", &["i", "m", "a", "c"]),
("sifive-s54", &["i", "m", "a", "f", "d", "c"]),
("sifive-s76", &["i", "m", "a", "f", "d", "c"]),
("sifive-u54", &["i", "m", "a", "f", "d", "c"]),
("sifive-u74", &["i", "m", "a", "f", "d", "c"]),
("rocket-rv32", &["i", "m", "a", "f", "d", "c"]),
("rocket-rv64", &["i", "m", "a", "f", "d", "c"]),
("boom-v1", &["i", "m", "a", "f", "d", "c"]),
("boom-v2", &["i", "m", "a", "f", "d", "c"]),
(
"boom-v3",
&["i", "m", "a", "f", "d", "c", "zba", "zbb", "zbs"],
),
("c906", &["i", "m", "a", "f", "d", "c", "v"]),
(
"c910",
&[
"i", "m", "a", "f", "d", "c", "v", "zba", "zbb", "zbc", "zbs",
],
),
(
"c920",
&[
"i", "m", "a", "f", "d", "c", "v", "zba", "zbb", "zbc", "zbs", "zkn", "zks",
],
),
("k210", &["i", "m", "a", "f", "d", "c"]),
(
"xiangshan-nanhu",
&[
"i", "m", "a", "f", "d", "c", "v", "zba", "zbb", "zbc", "zbs", "zkn",
],
),
(
"spacemit-x60",
&[
"i", "m", "a", "f", "d", "c", "zba", "zbb", "zbs", "zicbom", "zicboz", "zicbop",
],
),
("sg2042", &["i", "m", "a", "f", "d", "c", "v"]),
("c906fdv", &["i", "m", "a", "f", "d", "c", "v"]),
];
pub struct RiscVSubtarget {
pub is_64bit: bool,
pub cpu: String,
pub features: HashSet<String>,
pub has_m: bool,
pub has_a: bool,
pub has_f: bool,
pub has_d: bool,
pub has_c: bool,
pub has_v: bool,
pub has_zba: bool,
pub has_zbb: bool,
pub has_zbc: bool,
pub has_zbs: bool,
pub has_zicbom: bool,
pub has_zicboz: bool,
pub has_zicbop: bool,
pub has_zihintpause: bool,
pub has_zawrs: bool,
pub stack_alignment: u32,
pub max_inline_size: u32,
pub pref_vector_width: u32,
}
impl RiscVSubtarget {
pub fn new(triple: &str, cpu: &str, features: &str) -> Self {
let is_64bit = triple.to_lowercase().starts_with("riscv64");
let mut feature_set = Self::get_features_for_cpu(cpu);
Self::parse_feature_string(&mut feature_set, features);
let has_m = feature_set.contains("m");
let has_a = feature_set.contains("a");
let has_f = feature_set.contains("f");
let has_d = feature_set.contains("d");
let has_c = feature_set.contains("c");
let has_v = feature_set.contains("v");
let has_zba = feature_set.contains("zba");
let has_zbb = feature_set.contains("zbb");
let has_zbc = feature_set.contains("zbc");
let has_zbs = feature_set.contains("zbs");
let has_zicbom = feature_set.contains("zicbom");
let has_zicboz = feature_set.contains("zicboz");
let has_zicbop = feature_set.contains("zicbop");
let has_zihintpause = feature_set.contains("zihintpause");
let has_zawrs = feature_set.contains("zawrs");
let max_inline_size = if is_64bit { 128 } else { 64 };
let pref_vector_width = if has_v { 128 } else { 0 };
RiscVSubtarget {
is_64bit,
cpu: cpu.to_string(),
features: feature_set,
has_m,
has_a,
has_f,
has_d,
has_c,
has_v,
has_zba,
has_zbb,
has_zbc,
has_zbs,
has_zicbom,
has_zicboz,
has_zicbop,
has_zihintpause,
has_zawrs,
stack_alignment: 16,
max_inline_size,
pref_vector_width,
}
}
fn parse_feature_string(features: &mut HashSet<String>, feature_str: &str) {
if feature_str.is_empty() {
return;
}
for part in feature_str.split(',') {
let part = part.trim();
if part.is_empty() {
continue;
}
if let Some(ext) = part.strip_prefix('+') {
features.insert(ext.to_string());
if ext == "d" {
features.insert("f".to_string());
}
if ext == "v" {
features.insert("zve32x".to_string());
}
} else if let Some(ext) = part.strip_prefix('-') {
features.remove(ext);
if ext == "f" {
features.remove("d");
}
}
}
}
pub fn get_features_for_cpu(cpu: &str) -> HashSet<String> {
for &(name, feats) in KNOWN_CPUS {
if name == cpu {
return feats.iter().map(|s| s.to_string()).collect();
}
}
["i".to_string()].into_iter().collect()
}
pub fn has_hard_float(&self) -> bool {
self.has_f || self.has_d
}
pub fn has_double_float(&self) -> bool {
self.has_d
}
pub fn has_single_float(&self) -> bool {
self.has_f
}
pub fn has_compressed(&self) -> bool {
self.has_c
}
pub fn has_vector(&self) -> bool {
self.has_v
}
pub fn has_atomics(&self) -> bool {
self.has_a
}
pub fn has_muldiv(&self) -> bool {
self.has_m
}
pub fn has_bitmanip(&self) -> bool {
self.has_zba || self.has_zbb || self.has_zbc || self.has_zbs
}
pub fn has_cache_ops(&self) -> bool {
self.has_zicbom || self.has_zicboz || self.has_zicbop
}
pub fn xlen(&self) -> u32 {
if self.is_64bit {
64
} else {
32
}
}
pub fn flen(&self) -> u32 {
if self.has_d {
64
} else if self.has_f {
32
} else {
0
}
}
pub fn abi_name(&self) -> &'static str {
if self.is_64bit {
if self.has_d {
"lp64d"
} else if self.has_f {
"lp64f"
} else {
"lp64"
}
} else {
if self.has_d {
"ilp32d"
} else if self.has_f {
"ilp32f"
} else {
"ilp32"
}
}
}
pub fn isa_string(&self) -> String {
let mut s = if self.is_64bit {
"rv64i".to_string()
} else {
"rv32i".to_string()
};
if self.has_m {
s.push('m');
}
if self.has_a {
s.push('a');
}
if self.has_f {
s.push('f');
}
if self.has_d {
s.push('d');
}
if self.has_c {
s.push('c');
}
if self.has_v {
s.push('v');
}
s
}
pub fn describe(&self) -> String {
let mut feat_list: Vec<String> = Vec::new();
if self.has_m {
feat_list.push("m".to_string());
}
if self.has_a {
feat_list.push("a".to_string());
}
if self.has_f {
feat_list.push("f".to_string());
}
if self.has_d {
feat_list.push("d".to_string());
}
if self.has_c {
feat_list.push("c".to_string());
}
if self.has_v {
feat_list.push("v".to_string());
}
if self.has_zba {
feat_list.push("zba".to_string());
}
if self.has_zbb {
feat_list.push("zbb".to_string());
}
if self.has_zbc {
feat_list.push("zbc".to_string());
}
if self.has_zbs {
feat_list.push("zbs".to_string());
}
if self.has_zicbom {
feat_list.push("zicbom".to_string());
}
if self.has_zicboz {
feat_list.push("zicboz".to_string());
}
if self.has_zicbop {
feat_list.push("zicbop".to_string());
}
if self.has_zihintpause {
feat_list.push("zihintpause".to_string());
}
if self.has_zawrs {
feat_list.push("zawrs".to_string());
}
format!(
"RiscVSubtarget {{ cpu: \"{}\", is_64bit: {}, abi: {}, isa: {}, features: [{}] }}",
self.cpu,
self.is_64bit,
self.abi_name(),
self.isa_string(),
feat_list.join(", "),
)
}
pub fn full_isa_string(&self) -> String {
let mut s = if self.is_64bit {
"rv64".to_string()
} else {
"rv32".to_string()
};
let has_g = self.has_m && self.has_a && self.has_f && self.has_d && self.has_c;
if has_g {
s.push_str("gc");
} else {
s.push('i');
if self.has_m {
s.push('m');
}
if self.has_a {
s.push('a');
}
if self.has_f {
s.push('f');
}
if self.has_d {
s.push('d');
}
if self.has_c {
s.push('c');
}
}
if self.has_v {
s.push('v');
}
let mut z_exts: Vec<&str> = Vec::new();
if self.has_zawrs {
z_exts.push("zawrs");
}
if self.has_zba {
z_exts.push("zba");
}
if self.has_zbb {
z_exts.push("zbb");
}
if self.has_zbc {
z_exts.push("zbc");
}
if self.has_zbs {
z_exts.push("zbs");
}
if self.has_zicbom {
z_exts.push("zicbom");
}
if self.has_zicboz {
z_exts.push("zicboz");
}
if self.has_zicbop {
z_exts.push("zicbop");
}
if self.has_zihintpause {
z_exts.push("zihintpause");
}
z_exts.sort();
for ext in z_exts {
s.push('_');
s.push_str(ext);
}
s
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedModel {
InOrderSingleIssue,
InOrderDualIssue,
OutOfOrder3Wide,
OutOfOrder4Wide,
OutOfOrder6Wide,
OutOfOrderC910,
Generic,
}
impl RiscVSubtarget {
pub fn scheduling_model(&self) -> SchedModel {
match self.cpu.as_str() {
"sifive-e20" | "sifive-e24" | "sifive-e31" | "sifive-e34" => {
SchedModel::InOrderSingleIssue
}
"sifive-e76" => SchedModel::InOrderSingleIssue,
"sifive-s21" | "sifive-s51" | "sifive-s54" | "sifive-s76" => {
SchedModel::InOrderSingleIssue
}
"sifive-u54" => SchedModel::InOrderSingleIssue,
"sifive-u74" => SchedModel::InOrderDualIssue,
"rocket-rv32" | "rocket-rv64" => SchedModel::InOrderSingleIssue,
"boom-v1" => SchedModel::OutOfOrder3Wide,
"boom-v2" => SchedModel::OutOfOrder4Wide,
"boom-v3" => SchedModel::OutOfOrder6Wide,
"c906" | "c906fdv" => SchedModel::InOrderDualIssue,
"c910" => SchedModel::OutOfOrderC910,
"c920" => SchedModel::OutOfOrder4Wide,
"xiangshan-nanhu" => SchedModel::OutOfOrder6Wide,
"k210" => SchedModel::InOrderDualIssue,
"sg2042" => SchedModel::InOrderSingleIssue,
"spacemit-x60" => SchedModel::InOrderDualIssue,
_ => SchedModel::Generic,
}
}
pub fn issue_width(&self) -> u32 {
match self.scheduling_model() {
SchedModel::InOrderSingleIssue => 1,
SchedModel::InOrderDualIssue => 2,
SchedModel::OutOfOrder3Wide => 3,
SchedModel::OutOfOrder4Wide => 4,
SchedModel::OutOfOrder6Wide => 6,
SchedModel::OutOfOrderC910 => 3,
SchedModel::Generic => 2,
}
}
pub fn is_out_of_order(&self) -> bool {
matches!(
self.scheduling_model(),
SchedModel::OutOfOrder3Wide
| SchedModel::OutOfOrder4Wide
| SchedModel::OutOfOrder6Wide
| SchedModel::OutOfOrderC910
)
}
pub fn use_save_restore_libcalls(&self) -> bool {
match self.cpu.as_str() {
"sifive-e20" | "sifive-e24" | "sifive-e31" | "sifive-e34" => true,
"sifive-e76" => false, _ => false,
}
}
pub fn use_tp_for_tls(&self) -> bool {
true
}
pub fn use_atomic_abi_libcalls(&self) -> bool {
!self.has_a
}
pub fn enable_machine_outliner(&self) -> bool {
self.cpu.starts_with("sifive-e") || self.cpu == "generic-rv32"
}
pub fn loop_unroll_factor(&self) -> u32 {
match self.scheduling_model() {
SchedModel::InOrderSingleIssue => 2,
SchedModel::InOrderDualIssue => 4,
SchedModel::OutOfOrder3Wide => 4,
SchedModel::OutOfOrder4Wide => 6,
SchedModel::OutOfOrder6Wide => 8,
SchedModel::OutOfOrderC910 => 6,
SchedModel::Generic => 4,
}
}
pub fn scheduler_buffer_size(&self) -> u32 {
match self.scheduling_model() {
SchedModel::InOrderSingleIssue => 16,
SchedModel::InOrderDualIssue => 32,
SchedModel::OutOfOrder3Wide => 48,
SchedModel::OutOfOrder4Wide => 64,
SchedModel::OutOfOrder6Wide => 128,
SchedModel::OutOfOrderC910 => 64,
SchedModel::Generic => 32,
}
}
pub fn load_to_use_latency(&self) -> u32 {
match self.scheduling_model() {
SchedModel::InOrderSingleIssue => 2,
SchedModel::InOrderDualIssue => 3,
_ => 4, }
}
pub fn branch_mispredict_penalty(&self) -> u32 {
match self.scheduling_model() {
SchedModel::InOrderSingleIssue => 3,
SchedModel::InOrderDualIssue => 4,
SchedModel::OutOfOrder3Wide => 8,
SchedModel::OutOfOrder4Wide => 10,
SchedModel::OutOfOrder6Wide => 12,
SchedModel::OutOfOrderC910 => 10,
SchedModel::Generic => 5,
}
}
pub fn has_macro_fusion(&self) -> bool {
matches!(
self.scheduling_model(),
SchedModel::OutOfOrder3Wide
| SchedModel::OutOfOrder4Wide
| SchedModel::OutOfOrder6Wide
| SchedModel::OutOfOrderC910
)
}
pub fn enable_tail_duplication(&self) -> bool {
self.is_out_of_order()
}
pub fn prefer_predication(&self) -> bool {
self.branch_mispredict_penalty() >= 8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_generic_rv64() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(st.is_64bit);
assert_eq!(st.xlen(), 64);
assert!(!st.has_m);
assert!(!st.has_f);
assert!(!st.has_d);
assert!(!st.has_c);
}
#[test]
fn test_new_generic_rv32() {
let st = RiscVSubtarget::new("riscv32-unknown-elf", "generic-rv32", "");
assert!(!st.is_64bit);
assert_eq!(st.xlen(), 32);
}
#[test]
fn test_new_with_explicit_features() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m,+a,+f,+d,+c");
assert!(st.has_m);
assert!(st.has_a);
assert!(st.has_f);
assert!(st.has_d);
assert!(st.has_c);
assert!(st.has_hard_float());
assert!(st.has_double_float());
}
#[test]
fn test_new_with_feature_disable() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m,+a,+f,+d,+c,-c");
assert!(st.has_m);
assert!(!st.has_c);
}
#[test]
fn test_enabling_d_implies_f() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+d");
assert!(st.has_d);
assert!(st.has_f, "Enabling D should imply F");
}
#[test]
fn test_disabling_f_disables_d() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+d,-f");
assert!(!st.has_f);
assert!(!st.has_d, "Disabling F should disable D");
}
#[test]
fn test_vector_extension() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+v");
assert!(st.has_v);
assert!(st.has_vector());
assert_eq!(st.pref_vector_width, 128);
}
#[test]
fn test_bitmanip_extensions() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+zba,+zbb,+zbc,+zbs");
assert!(st.has_zba);
assert!(st.has_zbb);
assert!(st.has_zbc);
assert!(st.has_zbs);
assert!(st.has_bitmanip());
}
#[test]
fn test_cache_ops_extensions() {
let st = RiscVSubtarget::new(
"riscv64-unknown-elf",
"generic-rv64",
"+zicbom,+zicboz,+zicbop",
);
assert!(st.has_zicbom);
assert!(st.has_zicboz);
assert!(st.has_zicbop);
assert!(st.has_cache_ops());
}
#[test]
fn test_abi_name_lp64d() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+d");
assert_eq!(st.abi_name(), "lp64d");
}
#[test]
fn test_abi_name_lp64f() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+f");
assert_eq!(st.abi_name(), "lp64f");
}
#[test]
fn test_abi_name_lp64() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert_eq!(st.abi_name(), "lp64");
}
#[test]
fn test_abi_name_ilp32d() {
let st = RiscVSubtarget::new("riscv32-unknown-elf", "generic-rv32", "+d");
assert_eq!(st.abi_name(), "ilp32d");
}
#[test]
fn test_abi_name_ilp32() {
let st = RiscVSubtarget::new("riscv32-unknown-elf", "generic-rv32", "");
assert_eq!(st.abi_name(), "ilp32");
}
#[test]
fn test_isa_string() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m,+a,+f,+d,+c");
assert_eq!(st.isa_string(), "rv64imafdc");
let st32 = RiscVSubtarget::new("riscv32-unknown-elf", "generic-rv32", "+m,+a,+c");
assert_eq!(st32.isa_string(), "rv32imac");
}
#[test]
fn test_flen() {
let st_none = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert_eq!(st_none.flen(), 0);
let st_f = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+f");
assert_eq!(st_f.flen(), 32);
let st_d = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+d");
assert_eq!(st_d.flen(), 64);
}
#[test]
fn test_get_features_for_cpu_c906() {
let feats = RiscVSubtarget::get_features_for_cpu("c906");
assert!(feats.contains("v"));
assert!(feats.contains("f"));
assert!(feats.contains("d"));
}
#[test]
fn test_get_features_for_cpu_c910() {
let feats = RiscVSubtarget::get_features_for_cpu("c910");
assert!(feats.contains("zba"));
assert!(feats.contains("zbb"));
assert!(feats.contains("v"));
}
#[test]
fn test_get_features_for_cpu_unknown() {
let feats = RiscVSubtarget::get_features_for_cpu("unknown-cpu");
assert_eq!(feats.len(), 1);
assert!(feats.contains("i"));
}
#[test]
fn test_get_features_for_cpu_sifive_u54() {
let feats = RiscVSubtarget::get_features_for_cpu("sifive-u54");
assert!(feats.contains("i"));
assert!(feats.contains("m"));
assert!(feats.contains("a"));
assert!(feats.contains("f"));
assert!(feats.contains("d"));
assert!(feats.contains("c"));
}
#[test]
fn test_get_features_for_cpu_k210() {
let feats = RiscVSubtarget::get_features_for_cpu("k210");
assert!(feats.contains("f"));
assert!(feats.contains("d"));
assert!(feats.contains("c"));
}
#[test]
fn test_has_hard_float() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+f");
assert!(st.has_hard_float());
let st_no = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(!st_no.has_hard_float());
}
#[test]
fn test_has_atomics() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+a");
assert!(st.has_atomics());
let st_no = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(!st_no.has_atomics());
}
#[test]
fn test_has_muldiv() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m");
assert!(st.has_muldiv());
let st_no = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(!st_no.has_muldiv());
}
#[test]
fn test_describe() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "sifive-u54", "+m");
let desc = st.describe();
assert!(desc.contains("sifive-u54"));
assert!(desc.contains("rv64i"));
assert!(desc.contains("lp64d"));
}
#[test]
fn test_parse_empty_feature_string() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(st.features.contains("i"));
assert_eq!(st.features.len(), 1);
}
#[test]
fn test_parse_feature_string_with_spaces() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m, +a, +c");
assert!(st.has_m);
assert!(st.has_a);
assert!(st.has_c);
}
#[test]
fn test_hint_extensions() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+zihintpause,+zawrs");
assert!(st.has_zihintpause);
assert!(st.has_zawrs);
}
#[test]
fn test_scheduling_model_inorder() {
let st = RiscVSubtarget::new("riscv32-unknown-elf", "sifive-e31", "");
assert_eq!(st.scheduling_model(), SchedModel::InOrderSingleIssue);
assert_eq!(st.issue_width(), 1);
assert!(!st.is_out_of_order());
}
#[test]
fn test_scheduling_model_dual_issue() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "sifive-u74", "");
assert_eq!(st.scheduling_model(), SchedModel::InOrderDualIssue);
assert_eq!(st.issue_width(), 2);
}
#[test]
fn test_scheduling_model_ooo() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "boom-v2", "");
assert_eq!(st.scheduling_model(), SchedModel::OutOfOrder4Wide);
assert_eq!(st.issue_width(), 4);
assert!(st.is_out_of_order());
}
#[test]
fn test_scheduling_model_xiangshan() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "xiangshan-nanhu", "");
assert_eq!(st.scheduling_model(), SchedModel::OutOfOrder6Wide);
assert_eq!(st.issue_width(), 6);
}
#[test]
fn test_scheduling_model_c910() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "c910", "");
assert_eq!(st.scheduling_model(), SchedModel::OutOfOrderC910);
assert_eq!(st.issue_width(), 3);
}
#[test]
fn test_use_save_restore_libcalls() {
let st_embed = RiscVSubtarget::new("riscv32-unknown-elf", "sifive-e20", "");
assert!(st_embed.use_save_restore_libcalls());
let st_big = RiscVSubtarget::new("riscv64-unknown-elf", "sifive-u74", "");
assert!(!st_big.use_save_restore_libcalls());
}
#[test]
fn test_use_tp_for_tls() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(st.use_tp_for_tls());
}
#[test]
fn test_use_atomic_abi_libcalls() {
let st_no_a = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(st_no_a.use_atomic_abi_libcalls());
let st_with_a = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+a");
assert!(!st_with_a.use_atomic_abi_libcalls());
}
#[test]
fn test_enable_machine_outliner() {
let st_embed = RiscVSubtarget::new("riscv32-unknown-elf", "sifive-e31", "");
assert!(st_embed.enable_machine_outliner());
let st_big = RiscVSubtarget::new("riscv64-unknown-elf", "sifive-u74", "");
assert!(!st_big.enable_machine_outliner());
}
#[test]
fn test_loop_unroll_factor() {
let st_ino = RiscVSubtarget::new("riscv32-unknown-elf", "sifive-e31", "");
assert_eq!(st_ino.loop_unroll_factor(), 2);
let st_ooo = RiscVSubtarget::new("riscv64-unknown-elf", "boom-v2", "");
assert_eq!(st_ooo.loop_unroll_factor(), 6);
}
#[test]
fn test_scheduler_buffer_size() {
let st_ino = RiscVSubtarget::new("riscv32-unknown-elf", "sifive-e31", "");
assert_eq!(st_ino.scheduler_buffer_size(), 16);
let st_ooo = RiscVSubtarget::new("riscv64-unknown-elf", "xiangshan-nanhu", "");
assert_eq!(st_ooo.scheduler_buffer_size(), 128);
}
#[test]
fn test_load_to_use_latency() {
let st_ino = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert_eq!(st_ino.load_to_use_latency(), 2);
}
#[test]
fn test_branch_mispredict_penalty() {
let st_ino = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert_eq!(st_ino.branch_mispredict_penalty(), 5);
let st_ooo = RiscVSubtarget::new("riscv64-unknown-elf", "boom-v2", "");
assert_eq!(st_ooo.branch_mispredict_penalty(), 10);
}
#[test]
fn test_has_macro_fusion() {
let st_ino = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(!st_ino.has_macro_fusion());
let st_ooo = RiscVSubtarget::new("riscv64-unknown-elf", "boom-v2", "");
assert!(st_ooo.has_macro_fusion());
}
#[test]
fn test_full_isa_string() {
let st = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "+m,+a,+f,+d,+c");
assert_eq!(st.full_isa_string(), "rv64gc");
let st32 = RiscVSubtarget::new("riscv32-unknown-elf", "generic-rv32", "+m,+a,+c");
assert_eq!(st32.full_isa_string(), "rv32imac");
}
#[test]
fn test_full_isa_string_with_z_exts() {
let st = RiscVSubtarget::new(
"riscv64-unknown-elf",
"generic-rv64",
"+m,+a,+f,+d,+c,+zba,+zbb",
);
let isa = st.full_isa_string();
assert!(isa.starts_with("rv64gc"));
assert!(isa.contains("zba"));
assert!(isa.contains("zbb"));
}
#[test]
fn test_get_features_for_cpu_c920() {
let feats = RiscVSubtarget::get_features_for_cpu("c920");
assert!(feats.contains("v"));
assert!(feats.contains("zkn"));
assert!(feats.contains("zks"));
}
#[test]
fn test_get_features_for_xiangshan() {
let feats = RiscVSubtarget::get_features_for_cpu("xiangshan-nanhu");
assert!(feats.contains("v"));
assert!(feats.contains("zba"));
assert!(feats.contains("zbb"));
}
#[test]
fn test_prefer_predication() {
let st_ino = RiscVSubtarget::new("riscv64-unknown-elf", "generic-rv64", "");
assert!(!st_ino.prefer_predication());
let st_ooo = RiscVSubtarget::new("riscv64-unknown-elf", "xiangshan-nanhu", "");
assert!(st_ooo.prefer_predication());
}
}