#[allow(clippy::type_complexity)]
pub const IMPLICATIONS: &[(&str, &[&str])] = &[
("M", &["Zmmul"]), ("Zicntr", &["Zicsr"]), ("Zihpm", &["Zicsr"]), ("Ziccid", &["Ziccif"]), ("F", &["Zicsr"]), ("D", &["F"]), ("Q", &["D"]), ("Zfh", &["Zfhmin"]), ("Zfhmin", &["F"]), ("Zvfh", &["Zvfhmin", "Zfhmin"]), ("Zvfhmin", &["Zve32f"]), ("Zfinx", &["Zicsr"]), ("Zdinx", &["Zfinx"]), ("Zhinx", &["Zhinxmin"]), ("A", &["Zaamo", "Zalrsc"]), ("Zabha", &["Zaamo"]), ("Zacas", &["Zaamo"]), ("C", &["Zca"]), ("Zcb", &["Zca"]), ("Zcf", &["F", "Zca"]), ("Zcd", &["D", "Zca"]), ("Zce", &["Zca", "Zcb", "Zcmp", "Zcmt"]), ("B", &["Zba", "Zbb", "Zbs"]), ("Zbc", &["Zbkc"]), ("Zk", &["Zkn", "Zkr", "Zkt"]), ("Zkn", &["Zbkb", "Zbkc", "Zbkx", "Zkne", "Zknd", "Zknh"]), ("Zks", &["Zbkb", "Zbkc", "Zbkx", "Zksed", "Zksh"]), ("V", &["Zve64d", "Zvl128b"]), ("Zve64d", &["Zve64f", "D"]), ("Zve64f", &["Zve32f", "Zve64x"]), ("Zve64x", &["Zve32x", "Zvl64b"]), ("Zve32f", &["Zve32x", "F"]), ("Zvbb", &["Zvkb"]), ("Zvbc", &["Zve64x"]), ("Zvkb", &["Zve32x"]), ("Zvkned", &["Zve32x"]), ("Zvknha", &["Zve32x"]), ("Zvknhb", &["Zve64x", "Zvknha"]), ("Zvkn", &["Zvkned", "Zvknhb", "Zvkb", "Zvkt"]), ("Zvks", &["Zvksed", "Zvksh", "Zvkb", "Zvkt"]), ("Zvl65536b", &["Zvl32768b"]),
("Zvl32768b", &["Zvl16384b"]),
("Zvl16384b", &["Zvl8192b"]),
("Zvl8192b", &["Zvl4096b"]),
("Zvl4096b", &["Zvl2048b"]),
("Zvl2048b", &["Zvl1024b"]),
("Zvl1024b", &["Zvl512b"]),
("Zvl512b", &["Zvl256b"]),
("Zvl256b", &["Zvl128b"]),
("Zvl128b", &["Zvl64b"]),
("Zvl64b", &["Zvl32b"]),
];
pub const COMPOSITIONS: &[(&str, &[&str])] = &[
("A", &["Zaamo", "Zalrsc"]),
("B", &["Zba", "Zbb", "Zbs"]),
("Zce", &["Zca", "Zcb", "Zcmp", "Zcmt"]),
("Zk", &["Zkn", "Zkr", "Zkt"]),
("Zkn", &["Zbkb", "Zbkc", "Zbkx", "Zkne", "Zknd", "Zknh"]),
("Zks", &["Zbkb", "Zbkc", "Zbkx", "Zksed", "Zksh"]),
("Zvkn", &["Zvkned", "Zvknhb", "Zvkb", "Zvkt"]),
("Zvks", &["Zvksed", "Zvksh", "Zvkb", "Zvkt"]),
];
use std::collections::BTreeSet;
#[must_use]
pub fn compute_derived(explicit: &BTreeSet<String>) -> BTreeSet<String> {
let mut known: BTreeSet<String> = explicit.clone();
let mut derived: BTreeSet<String> = BTreeSet::new();
loop {
let mut changed = false;
for &(name, implies) in IMPLICATIONS {
if known.contains(name) {
for &imp in implies {
if known.insert(imp.to_string()) {
derived.insert(imp.to_string());
changed = true;
}
}
}
}
for &(name, requires) in COMPOSITIONS {
if !known.contains(name) && requires.iter().all(|r| known.contains(*r)) {
known.insert(name.to_string());
derived.insert(name.to_string());
changed = true;
}
}
if !changed {
break;
}
}
derived
}
#[cfg(test)]
mod tests {
use super::*;
fn set(names: &[&str]) -> BTreeSet<String> {
names.iter().map(|s| s.to_string()).collect()
}
#[test]
fn m_implies_zmmul() {
let derived = compute_derived(&set(&["M"]));
assert!(derived.contains("Zmmul"));
}
#[test]
fn zihpm_implies_zicsr() {
let derived = compute_derived(&set(&["Zihpm"]));
assert!(derived.contains("Zicsr"));
}
#[test]
fn zba_zbb_zbs_compose_into_b() {
let derived = compute_derived(&set(&["Zba", "Zbb", "Zbs"]));
assert!(derived.contains("B"));
}
#[test]
fn zba_alone_does_not_compose_into_b() {
let derived = compute_derived(&set(&["Zba"]));
assert!(!derived.contains("B"));
}
#[test]
fn v_transitively_implies_zve32x() {
let derived = compute_derived(&set(&["V"]));
assert!(derived.contains("Zve64d"));
assert!(derived.contains("Zve64f"));
assert!(derived.contains("Zve32f"));
assert!(derived.contains("Zve32x"));
assert!(derived.contains("Zve64x"));
assert!(derived.contains("D"));
assert!(derived.contains("F"));
assert!(derived.contains("Zicsr"));
}
#[test]
fn explicit_extensions_are_not_marked_derived() {
let derived = compute_derived(&set(&["B", "Zba", "Zbb", "Zbs"]));
assert!(!derived.contains("B"));
assert!(!derived.contains("Zba"));
}
#[test]
fn no_infinite_loop_on_empty_input() {
let derived = compute_derived(&BTreeSet::new());
assert!(derived.is_empty());
}
}