use crate::{
analysis::{consts::ConstEvaluator, evaluator::SsaEvaluator, phis::PhiAnalyzer},
ir::{function::SsaFunction, value::ConstValue, variable::SsaVarId},
target::Target,
PointerSize,
};
pub struct ValueResolver<'a, T: Target> {
ssa: &'a SsaFunction<T>,
evaluator: ConstEvaluator<'a, T>,
phi: PhiAnalyzer<'a, T>,
resolve_phis: bool,
path_aware_fallback: bool,
ptr_size: PointerSize,
}
impl<'a, T: Target> ValueResolver<'a, T> {
#[must_use]
pub fn new(ssa: &'a SsaFunction<T>, ptr_size: PointerSize) -> Self {
Self {
ssa,
evaluator: ConstEvaluator::new(ssa, ptr_size),
phi: PhiAnalyzer::new(ssa),
resolve_phis: true,
path_aware_fallback: false,
ptr_size,
}
}
#[must_use]
pub fn with_path_aware_fallback(mut self) -> Self {
self.path_aware_fallback = true;
self
}
pub fn set_known(&mut self, var: SsaVarId, value: ConstValue<T>) {
self.evaluator.set_known(var, value);
}
pub fn resolve(&mut self, var: SsaVarId) -> Option<ConstValue<T>> {
if let Some(val) = self.evaluator.evaluate_var(var) {
return Some(val);
}
if self.resolve_phis {
if let Some((_, phi)) = self.ssa.find_phi_defining(var) {
let result = self.phi.uniform_constant(phi, &mut self.evaluator);
if result.is_some() {
return result;
}
}
}
if self.path_aware_fallback && self.ssa.get_definition(var).is_some() {
let mut eval = SsaEvaluator::new(self.ssa, self.ptr_size);
if let Some(resolved) = eval.resolve_with_trace(var, 15) {
if let Some(c) = resolved.as_constant() {
self.evaluator.set_known(var, c.clone());
return Some(c.clone());
}
}
}
None
}
pub fn resolve_all(&mut self, vars: &[SsaVarId]) -> Option<Vec<ConstValue<T>>> {
let mut result = Vec::with_capacity(vars.len());
for &var in vars {
result.push(self.resolve(var)?);
}
Some(result)
}
}