use crate::{JitError, JitResult};
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub enum AbstractDomainType {
Intervals,
Signs,
Constants,
Polyhedra,
Octagons,
}
#[derive(Debug, Clone)]
pub enum AbstractValue {
Interval { min: f64, max: f64 },
Sign(SignValue),
Constant(ConstantValue),
Polyhedron(Vec<LinearConstraint>),
Octagon(OctagonConstraints),
}
impl AbstractValue {
pub fn precision(&self) -> f64 {
match self {
AbstractValue::Interval { min, max } => {
if min == max {
1.0
} else if max.is_infinite() || min.is_infinite() {
0.0
} else {
1.0 / (max - min + 1.0)
}
}
AbstractValue::Constant(ConstantValue::Value(_)) => 1.0,
AbstractValue::Constant(ConstantValue::Top) => 0.0,
AbstractValue::Sign(SignValue::Zero) => 1.0,
AbstractValue::Sign(SignValue::Top) => 0.0,
_ => 0.5,
}
}
pub fn is_constant(&self) -> bool {
matches!(
self,
AbstractValue::Interval { min, max } if min == max
) || matches!(self, AbstractValue::Constant(ConstantValue::Value(_)))
|| matches!(self, AbstractValue::Sign(SignValue::Zero))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SignValue {
Bottom,
Zero,
Positive,
Negative,
NonPositive,
NonNegative,
Top,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ConstantValue {
Bottom,
Value(f64),
Top,
}
#[derive(Debug, Clone)]
pub enum LinearConstraint {
True,
False,
LessEqual(Vec<f64>, f64), }
#[derive(Debug, Clone)]
pub struct OctagonConstraints {
pub dbm: Vec<Vec<f64>>,
pub var_count: usize,
}
impl OctagonConstraints {
pub fn new(var_count: usize) -> Self {
let size = 2 * var_count;
Self {
dbm: vec![vec![f64::INFINITY; size]; size],
var_count,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum BinaryAbstractOp {
Add,
Sub,
Mul,
Div,
Mod,
Equal,
NotEqual,
Less,
LessEqual,
Greater,
GreaterEqual,
}
#[derive(Debug, Clone, Copy)]
pub enum UnaryAbstractOp {
Neg,
Abs,
Sqrt,
Sin,
Cos,
Exp,
Log,
}
pub trait AbstractDomain: Debug {
fn bottom(&self) -> AbstractValue;
fn top(&self) -> AbstractValue;
fn join(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue>;
fn meet(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue>;
fn widen(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue>;
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue>;
fn less_equal(&self, a: &AbstractValue, b: &AbstractValue) -> bool;
fn abstract_binary_op(
&self,
op: BinaryAbstractOp,
left: &AbstractValue,
right: &AbstractValue,
) -> JitResult<AbstractValue>;
fn abstract_unary_op(
&self,
op: UnaryAbstractOp,
operand: &AbstractValue,
) -> JitResult<AbstractValue>;
fn lift_constant(&self, value: f64) -> JitResult<AbstractValue>;
fn concretize(&self, value: &AbstractValue) -> Option<Vec<f64>>;
}
pub struct AbstractDomainFactory;
impl AbstractDomainFactory {
pub fn new() -> Self {
Self
}
pub fn create_domain(&self, domain_type: &AbstractDomainType) -> Box<dyn AbstractDomain> {
match domain_type {
AbstractDomainType::Intervals => Box::new(IntervalDomain::new()),
AbstractDomainType::Signs => Box::new(SignDomain::new()),
AbstractDomainType::Constants => Box::new(ConstantDomain::new()),
AbstractDomainType::Polyhedra => Box::new(PolyhedralDomain::new()),
AbstractDomainType::Octagons => Box::new(OctagonDomain::new()),
}
}
}
impl Default for AbstractDomainFactory {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct IntervalDomain;
impl IntervalDomain {
pub fn new() -> Self {
Self
}
}
impl Default for IntervalDomain {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for IntervalDomain {
fn bottom(&self) -> AbstractValue {
AbstractValue::Interval {
min: f64::INFINITY,
max: f64::NEG_INFINITY,
}
}
fn top(&self) -> AbstractValue {
AbstractValue::Interval {
min: f64::NEG_INFINITY,
max: f64::INFINITY,
}
}
fn join(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(
AbstractValue::Interval {
min: min1,
max: max1,
},
AbstractValue::Interval {
min: min2,
max: max2,
},
) => Ok(AbstractValue::Interval {
min: min1.min(*min2),
max: max1.max(*max2),
}),
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in interval join".to_string(),
)),
}
}
fn meet(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(
AbstractValue::Interval {
min: min1,
max: max1,
},
AbstractValue::Interval {
min: min2,
max: max2,
},
) => {
let new_min = min1.max(*min2);
let new_max = max1.min(*max2);
if new_min <= new_max {
Ok(AbstractValue::Interval {
min: new_min,
max: new_max,
})
} else {
Ok(self.bottom())
}
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in interval meet".to_string(),
)),
}
}
fn widen(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(
AbstractValue::Interval {
min: min1,
max: max1,
},
AbstractValue::Interval {
min: min2,
max: max2,
},
) => {
let new_min = if min2 < min1 {
f64::NEG_INFINITY
} else {
*min1
};
let new_max = if max2 > max1 { f64::INFINITY } else { *max1 };
Ok(AbstractValue::Interval {
min: new_min,
max: new_max,
})
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in interval widening".to_string(),
)),
}
}
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
self.meet(a, b)
}
fn less_equal(&self, a: &AbstractValue, b: &AbstractValue) -> bool {
match (a, b) {
(
AbstractValue::Interval {
min: min1,
max: max1,
},
AbstractValue::Interval {
min: min2,
max: max2,
},
) => min2 <= min1 && max1 <= max2,
_ => false,
}
}
fn abstract_binary_op(
&self,
op: BinaryAbstractOp,
left: &AbstractValue,
right: &AbstractValue,
) -> JitResult<AbstractValue> {
match (left, right) {
(
AbstractValue::Interval {
min: min1,
max: max1,
},
AbstractValue::Interval {
min: min2,
max: max2,
},
) => {
match op {
BinaryAbstractOp::Add => Ok(AbstractValue::Interval {
min: min1 + min2,
max: max1 + max2,
}),
BinaryAbstractOp::Sub => Ok(AbstractValue::Interval {
min: min1 - max2,
max: max1 - min2,
}),
BinaryAbstractOp::Mul => {
let products = [min1 * min2, min1 * max2, max1 * min2, max1 * max2];
Ok(AbstractValue::Interval {
min: products.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
max: products.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)),
})
}
BinaryAbstractOp::Div => {
if *min2 <= 0.0 && 0.0 <= *max2 {
Ok(self.top())
} else {
let quotients = [min1 / min2, min1 / max2, max1 / min2, max1 / max2];
Ok(AbstractValue::Interval {
min: quotients.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
max: quotients.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)),
})
}
}
_ => Ok(self.top()), }
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in interval binary operation".to_string(),
)),
}
}
fn abstract_unary_op(
&self,
op: UnaryAbstractOp,
operand: &AbstractValue,
) -> JitResult<AbstractValue> {
match operand {
AbstractValue::Interval { min, max } => {
match op {
UnaryAbstractOp::Neg => Ok(AbstractValue::Interval {
min: -max,
max: -min,
}),
UnaryAbstractOp::Abs => {
if *min >= 0.0 {
Ok(AbstractValue::Interval {
min: *min,
max: *max,
})
} else if *max <= 0.0 {
Ok(AbstractValue::Interval {
min: -max,
max: -min,
})
} else {
Ok(AbstractValue::Interval {
min: 0.0,
max: min.abs().max(max.abs()),
})
}
}
_ => Ok(self.top()), }
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in interval unary operation".to_string(),
)),
}
}
fn lift_constant(&self, value: f64) -> JitResult<AbstractValue> {
Ok(AbstractValue::Interval {
min: value,
max: value,
})
}
fn concretize(&self, value: &AbstractValue) -> Option<Vec<f64>> {
match value {
AbstractValue::Interval { min, max } => {
if min == max {
Some(vec![*min])
} else {
None }
}
_ => None,
}
}
}
#[derive(Debug)]
pub struct SignDomain;
impl SignDomain {
pub fn new() -> Self {
Self
}
}
impl Default for SignDomain {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for SignDomain {
fn bottom(&self) -> AbstractValue {
AbstractValue::Sign(SignValue::Bottom)
}
fn top(&self) -> AbstractValue {
AbstractValue::Sign(SignValue::Top)
}
fn join(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(AbstractValue::Sign(s1), AbstractValue::Sign(s2)) => {
let result = self.join_sign_values(s1, s2);
Ok(AbstractValue::Sign(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in sign join".to_string(),
)),
}
}
fn meet(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(AbstractValue::Sign(s1), AbstractValue::Sign(s2)) => {
let result = self.meet_sign_values(s1, s2);
Ok(AbstractValue::Sign(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in sign meet".to_string(),
)),
}
}
fn widen(&self, a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(a.clone())
}
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
self.meet(a, b)
}
fn less_equal(&self, a: &AbstractValue, b: &AbstractValue) -> bool {
match (a, b) {
(AbstractValue::Sign(s1), AbstractValue::Sign(s2)) => self.sign_less_equal(s1, s2),
_ => false,
}
}
fn abstract_binary_op(
&self,
op: BinaryAbstractOp,
left: &AbstractValue,
right: &AbstractValue,
) -> JitResult<AbstractValue> {
match (left, right) {
(AbstractValue::Sign(s1), AbstractValue::Sign(s2)) => {
let result = match op {
BinaryAbstractOp::Add => self.add_sign_values(s1, s2),
BinaryAbstractOp::Sub => self.sub_sign_values(s1, s2),
BinaryAbstractOp::Mul => self.mul_sign_values(s1, s2),
BinaryAbstractOp::Div => self.div_sign_values(s1, s2),
_ => SignValue::Top, };
Ok(AbstractValue::Sign(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in sign binary operation".to_string(),
)),
}
}
fn abstract_unary_op(
&self,
op: UnaryAbstractOp,
operand: &AbstractValue,
) -> JitResult<AbstractValue> {
match operand {
AbstractValue::Sign(s) => {
let result = match op {
UnaryAbstractOp::Neg => self.neg_sign_value(s),
UnaryAbstractOp::Abs => self.abs_sign_value(s),
_ => SignValue::Top, };
Ok(AbstractValue::Sign(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in sign unary operation".to_string(),
)),
}
}
fn lift_constant(&self, value: f64) -> JitResult<AbstractValue> {
let sign = if value > 0.0 {
SignValue::Positive
} else if value < 0.0 {
SignValue::Negative
} else {
SignValue::Zero
};
Ok(AbstractValue::Sign(sign))
}
fn concretize(&self, value: &AbstractValue) -> Option<Vec<f64>> {
match value {
AbstractValue::Sign(SignValue::Zero) => Some(vec![0.0]),
_ => None, }
}
}
impl SignDomain {
fn join_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
use SignValue::*;
match (s1, s2) {
(Bottom, s) | (s, Bottom) => s.clone(),
(Top, _) | (_, Top) => Top,
(s1, s2) if s1 == s2 => s1.clone(),
(Zero, Positive) | (Positive, Zero) => NonNegative,
(Zero, Negative) | (Negative, Zero) => NonPositive,
(Positive, Negative) | (Negative, Positive) => Top,
(NonPositive, Positive) | (Positive, NonPositive) => Top,
(NonNegative, Negative) | (Negative, NonNegative) => Top,
(NonPositive, NonNegative) | (NonNegative, NonPositive) => Top,
_ => Top,
}
}
fn meet_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
use SignValue::*;
match (s1, s2) {
(Top, s) | (s, Top) => s.clone(),
(Bottom, _) | (_, Bottom) => Bottom,
(s1, s2) if s1 == s2 => s1.clone(),
(NonNegative, Positive) | (Positive, NonNegative) => Positive,
(NonNegative, Zero) | (Zero, NonNegative) => Zero,
(NonPositive, Negative) | (Negative, NonPositive) => Negative,
(NonPositive, Zero) | (Zero, NonPositive) => Zero,
_ => Bottom,
}
}
fn sign_less_equal(&self, s1: &SignValue, s2: &SignValue) -> bool {
use SignValue::*;
match (s1, s2) {
(Bottom, _) => true,
(_, Top) => true,
(s1, s2) if s1 == s2 => true,
(Zero, NonNegative) | (Zero, NonPositive) => true,
(Positive, NonNegative) => true,
(Negative, NonPositive) => true,
_ => false,
}
}
fn add_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
use SignValue::*;
match (s1, s2) {
(Bottom, _) | (_, Bottom) => Bottom,
(Top, _) | (_, Top) => Top,
(Zero, s) | (s, Zero) => s.clone(),
(Positive, Positive) => Positive,
(Negative, Negative) => Negative,
(Positive, Negative) | (Negative, Positive) => Top,
_ => Top,
}
}
fn sub_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
let neg_s2 = self.neg_sign_value(s2);
self.add_sign_values(s1, &neg_s2)
}
fn mul_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
use SignValue::*;
match (s1, s2) {
(Bottom, _) | (_, Bottom) => Bottom,
(Top, _) | (_, Top) => Top,
(Zero, _) | (_, Zero) => Zero,
(Positive, Positive) | (Negative, Negative) => Positive,
(Positive, Negative) | (Negative, Positive) => Negative,
_ => Top,
}
}
fn div_sign_values(&self, s1: &SignValue, s2: &SignValue) -> SignValue {
use SignValue::*;
match (s1, s2) {
(Bottom, _) | (_, Bottom) => Bottom,
(_, Zero) => Bottom, (Zero, _) => Zero,
_ => self.mul_sign_values(s1, s2), }
}
fn neg_sign_value(&self, s: &SignValue) -> SignValue {
use SignValue::*;
match s {
Bottom => Bottom,
Top => Top,
Zero => Zero,
Positive => Negative,
Negative => Positive,
NonPositive => NonNegative,
NonNegative => NonPositive,
}
}
fn abs_sign_value(&self, s: &SignValue) -> SignValue {
use SignValue::*;
match s {
Bottom => Bottom,
Top => NonNegative,
Zero => Zero,
Positive => Positive,
Negative => Positive,
NonPositive => NonNegative,
NonNegative => NonNegative,
}
}
}
#[derive(Debug)]
pub struct ConstantDomain;
impl ConstantDomain {
pub fn new() -> Self {
Self
}
}
impl Default for ConstantDomain {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for ConstantDomain {
fn bottom(&self) -> AbstractValue {
AbstractValue::Constant(ConstantValue::Bottom)
}
fn top(&self) -> AbstractValue {
AbstractValue::Constant(ConstantValue::Top)
}
fn join(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(AbstractValue::Constant(c1), AbstractValue::Constant(c2)) => {
let result = match (c1, c2) {
(ConstantValue::Bottom, c) | (c, ConstantValue::Bottom) => c.clone(),
(ConstantValue::Top, _) | (_, ConstantValue::Top) => ConstantValue::Top,
(ConstantValue::Value(v1), ConstantValue::Value(v2)) => {
if v1 == v2 {
ConstantValue::Value(*v1)
} else {
ConstantValue::Top
}
}
};
Ok(AbstractValue::Constant(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in constant join".to_string(),
)),
}
}
fn meet(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
match (a, b) {
(AbstractValue::Constant(c1), AbstractValue::Constant(c2)) => {
let result = match (c1, c2) {
(ConstantValue::Top, c) | (c, ConstantValue::Top) => c.clone(),
(ConstantValue::Bottom, _) | (_, ConstantValue::Bottom) => {
ConstantValue::Bottom
}
(ConstantValue::Value(v1), ConstantValue::Value(v2)) => {
if v1 == v2 {
ConstantValue::Value(*v1)
} else {
ConstantValue::Bottom
}
}
};
Ok(AbstractValue::Constant(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in constant meet".to_string(),
)),
}
}
fn widen(&self, a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(a.clone())
}
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
self.meet(a, b)
}
fn less_equal(&self, a: &AbstractValue, b: &AbstractValue) -> bool {
match (a, b) {
(AbstractValue::Constant(c1), AbstractValue::Constant(c2)) => match (c1, c2) {
(ConstantValue::Bottom, _) => true,
(_, ConstantValue::Top) => true,
(ConstantValue::Value(v1), ConstantValue::Value(v2)) => v1 == v2,
_ => false,
},
_ => false,
}
}
fn abstract_binary_op(
&self,
op: BinaryAbstractOp,
left: &AbstractValue,
right: &AbstractValue,
) -> JitResult<AbstractValue> {
match (left, right) {
(AbstractValue::Constant(c1), AbstractValue::Constant(c2)) => {
let result = match (c1, c2) {
(ConstantValue::Value(v1), ConstantValue::Value(v2)) => {
match op {
BinaryAbstractOp::Add => ConstantValue::Value(v1 + v2),
BinaryAbstractOp::Sub => ConstantValue::Value(v1 - v2),
BinaryAbstractOp::Mul => ConstantValue::Value(v1 * v2),
BinaryAbstractOp::Div => {
if *v2 != 0.0 {
ConstantValue::Value(v1 / v2)
} else {
ConstantValue::Bottom }
}
_ => ConstantValue::Top, }
}
(ConstantValue::Bottom, _) | (_, ConstantValue::Bottom) => {
ConstantValue::Bottom
}
_ => ConstantValue::Top,
};
Ok(AbstractValue::Constant(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in constant binary operation".to_string(),
)),
}
}
fn abstract_unary_op(
&self,
op: UnaryAbstractOp,
operand: &AbstractValue,
) -> JitResult<AbstractValue> {
match operand {
AbstractValue::Constant(c) => {
let result = match c {
ConstantValue::Value(v) => {
match op {
UnaryAbstractOp::Neg => ConstantValue::Value(-v),
UnaryAbstractOp::Abs => ConstantValue::Value(v.abs()),
UnaryAbstractOp::Sqrt => {
if *v >= 0.0 {
ConstantValue::Value(v.sqrt())
} else {
ConstantValue::Bottom }
}
_ => ConstantValue::Top, }
}
ConstantValue::Bottom => ConstantValue::Bottom,
ConstantValue::Top => ConstantValue::Top,
};
Ok(AbstractValue::Constant(result))
}
_ => Err(JitError::AbstractInterpretationError(
"Type mismatch in constant unary operation".to_string(),
)),
}
}
fn lift_constant(&self, value: f64) -> JitResult<AbstractValue> {
Ok(AbstractValue::Constant(ConstantValue::Value(value)))
}
fn concretize(&self, value: &AbstractValue) -> Option<Vec<f64>> {
match value {
AbstractValue::Constant(ConstantValue::Value(v)) => Some(vec![*v]),
_ => None,
}
}
}
#[derive(Debug)]
pub struct PolyhedralDomain;
impl PolyhedralDomain {
pub fn new() -> Self {
Self
}
}
impl Default for PolyhedralDomain {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for PolyhedralDomain {
fn bottom(&self) -> AbstractValue {
AbstractValue::Polyhedron(vec![LinearConstraint::False])
}
fn top(&self) -> AbstractValue {
AbstractValue::Polyhedron(vec![LinearConstraint::True])
}
fn join(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn meet(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn widen(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
self.meet(a, b)
}
fn less_equal(&self, _a: &AbstractValue, _b: &AbstractValue) -> bool {
false
}
fn abstract_binary_op(
&self,
_op: BinaryAbstractOp,
_left: &AbstractValue,
_right: &AbstractValue,
) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn abstract_unary_op(
&self,
_op: UnaryAbstractOp,
_operand: &AbstractValue,
) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn lift_constant(&self, _value: f64) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn concretize(&self, _value: &AbstractValue) -> Option<Vec<f64>> {
None
}
}
#[derive(Debug)]
pub struct OctagonDomain;
impl OctagonDomain {
pub fn new() -> Self {
Self
}
}
impl Default for OctagonDomain {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for OctagonDomain {
fn bottom(&self) -> AbstractValue {
AbstractValue::Octagon(OctagonConstraints::new(0))
}
fn top(&self) -> AbstractValue {
AbstractValue::Octagon(OctagonConstraints::new(0))
}
fn join(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn meet(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn widen(&self, _a: &AbstractValue, _b: &AbstractValue) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn narrow(&self, a: &AbstractValue, b: &AbstractValue) -> JitResult<AbstractValue> {
self.meet(a, b)
}
fn less_equal(&self, _a: &AbstractValue, _b: &AbstractValue) -> bool {
false
}
fn abstract_binary_op(
&self,
_op: BinaryAbstractOp,
_left: &AbstractValue,
_right: &AbstractValue,
) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn abstract_unary_op(
&self,
_op: UnaryAbstractOp,
_operand: &AbstractValue,
) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn lift_constant(&self, _value: f64) -> JitResult<AbstractValue> {
Ok(self.top())
}
fn concretize(&self, _value: &AbstractValue) -> Option<Vec<f64>> {
None
}
}