use crate::detect::{Feature, cache};
pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initializer {
loop {
let prev = value;
macro_rules! imply {
($($from: ident)|+ => $($to: ident)&+) => {
if [$(Feature::$from as u32),+].iter().any(|&x| value.test(x)) {
$(
value.set(Feature::$to as u32);
)+
}
};
($($from: ident)&+ => $($to: ident)&+) => {
if [$(Feature::$from as u32),+].iter().all(|&x| value.test(x)) {
$(
value.set(Feature::$to as u32);
)+
}
};
}
macro_rules! group {
($group: ident == $($member: ident)&+) => {
imply!($group => $($member)&+);
imply!($($member)&+ => $group);
};
}
imply!(zvbb => zvkb);
group!(zvkn == zvkned & zvknhb & zvkb & zvkt);
group!(zvknc == zvkn & zvbc);
group!(zvkng == zvkn & zvkg);
group!(zvks == zvksed & zvksh & zvkb & zvkt);
group!(zvksc == zvks & zvbc);
group!(zvksg == zvks & zvkg);
imply!(zvknhb => zvknha);
imply!(zvknhb | zvbc => zve64x);
imply!(zvbb | zvkb | zvkg | zvkned | zvknha | zvksed | zvksh => zve32x);
imply!(zbc => zbkc); group!(zkn == zbkb & zbkc & zbkx & zkne & zknd & zknh);
group!(zks == zbkb & zbkc & zbkx & zksed & zksh);
group!(zk == zkn & zkr & zkt);
imply!(zacas => zaamo);
group!(a == zalrsc & zaamo);
group!(b == zba & zbb & zbs);
imply!(zcf => zca & f);
imply!(zcd => zca & d);
imply!(zcmop | zcb => zca);
imply!(zhinx => zhinxmin);
imply!(zdinx | zhinxmin => zfinx);
imply!(zvfh => zvfhmin); imply!(zvfh => zve32f & zfhmin);
imply!(zvfhmin => zve32f);
imply!(zvfbfwma => zvfbfmin & zfbfmin);
imply!(zvfbfmin => zve32f);
imply!(v => zve64d);
imply!(zve64d => zve64f & d);
imply!(zve64f => zve64x & zve32f);
imply!(zve64x => zve32x);
imply!(zve32f => zve32x & f);
imply!(zfh => zfhmin);
imply!(q => d);
imply!(d | zfhmin | zfa => f);
imply!(zfbfmin => f);
imply!(c => zca);
imply!(c & d => zcd);
#[cfg(target_arch = "riscv32")]
imply!(c & f => zcf);
imply!(zicntr | zihpm | f | zfinx | zve32x => zicsr);
if prev == value {
return value;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_direct() {
let mut value = cache::Initializer::default();
value.set(Feature::f as u32);
assert!(imply_features(value).test(Feature::zicsr as u32));
}
#[test]
fn simple_indirect() {
let mut value = cache::Initializer::default();
value.set(Feature::q as u32);
assert!(imply_features(value).test(Feature::zicsr as u32));
}
#[test]
fn complex_zcd() {
let mut value = cache::Initializer::default();
value.set(Feature::c as u32);
assert!(!imply_features(value).test(Feature::zcd as u32));
value.set(Feature::d as u32);
assert!(imply_features(value).test(Feature::zcd as u32));
}
#[test]
fn group_simple_forward() {
let mut value = cache::Initializer::default();
value.set(Feature::a as u32);
let value = imply_features(value);
assert!(value.test(Feature::zalrsc as u32));
assert!(value.test(Feature::zaamo as u32));
}
#[test]
fn group_simple_backward() {
let mut value = cache::Initializer::default();
value.set(Feature::zalrsc as u32);
value.set(Feature::zaamo as u32);
assert!(imply_features(value).test(Feature::a as u32));
}
#[test]
fn group_complex_convergence() {
let mut value = cache::Initializer::default();
value.set(Feature::zvksc as u32);
value.set(Feature::zvkned as u32);
value.set(Feature::zvknhb as u32);
value.set(Feature::zvkb as u32);
let value = imply_features(value);
assert!(value.test(Feature::zvkn as u32));
assert!(value.test(Feature::zvknc as u32));
}
}