liblisa-synth 0.3.0

A tool for automated discovery and analysis of the ISA of a CPU.
use std::fmt;

use liblisa::semantics::default::computation::{AsComputationRef, SynthesizedComputation};
use liblisa::utils::bitmap::GrowingBitmap;
use liblisa::value::AsValue;

use crate::predicate::Disjunction;

#[derive(Clone, Debug)]
pub struct SwitchCase {
    condition: Disjunction,
    index: usize,
}

impl SwitchCase {
    pub fn new(condition: Disjunction, index: usize) -> Self {
        Self {
            condition,
            index,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Switch {
    cases: Vec<SwitchCase>,
}

impl Switch {
    pub fn new() -> Self {
        Self {
            cases: Vec::new(),
        }
    }

    pub fn instantiate_with_outputs(&self, outputs: &[SynthesizedComputation]) -> SynthesizedComputation {
        let mut result = outputs[self.cases[self.cases.len() - 1].index].clone();

        for group in self.cases.iter().rev().skip(1) {
            let condition = SynthesizedComputation::from(group.condition.clone());
            let output = &outputs[group.index];
            result = condition.if_zero(&result, output);
        }

        result
    }

    pub fn used_input_indices(&self) -> Vec<usize> {
        let mut seen = GrowingBitmap::new();
        self.cases
            .iter()
            .flat_map(|group| group.condition.used_input_indices())
            .filter(|&n| seen.set(n))
            .collect()
    }

    pub fn remap_inputs(&mut self, map: &[Option<usize>]) {
        for case in self.cases.iter_mut() {
            case.condition.remap_inputs(map);
        }
    }

    pub fn add_case(&mut self, case: SwitchCase) {
        self.cases.push(case);
    }

    pub fn conditions(&self) -> impl Iterator<Item = &Disjunction> {
        self.cases.iter().map(|case| &case.condition)
    }
}

impl Default for Switch {
    fn default() -> Self {
        Self {
            cases: vec![SwitchCase {
                condition: Disjunction::always_true(),
                index: 0,
            }],
        }
    }
}

impl Switch {
    pub fn evaluate<V: AsValue>(&self, inputs: &[V]) -> usize {
        for group in self.cases.iter() {
            if group.condition.evaluate(inputs) {
                return group.index;
            }
        }

        panic!("This should not happen!")
    }

    pub fn display<'a, S: AsRef<str>>(&'a self, input_names: &'a [S]) -> DisplaySwitch<'a> {
        DisplaySwitch(self, input_names.iter().map(|s| s.as_ref().to_string()).collect::<Vec<_>>())
    }
}

#[derive(Debug)]
pub struct DisplaySwitch<'a>(&'a Switch, Vec<String>);

impl fmt::Display for DisplaySwitch<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "match {{ ")?;

        for case in self.0.cases.iter() {
            write!(f, "{} => {:X?}, ", case.condition.display(&self.1), case.index)?;
        }

        write!(f, "}}")
    }
}