From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001
From: Valentin Popov <valentin@popov.link>
Date: Mon, 8 Jan 2024 01:21:28 +0400
Subject: Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
---
 vendor/gimli/src/read/value.rs | 1621 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1621 insertions(+)
 create mode 100644 vendor/gimli/src/read/value.rs

(limited to 'vendor/gimli/src/read/value.rs')

diff --git a/vendor/gimli/src/read/value.rs b/vendor/gimli/src/read/value.rs
new file mode 100644
index 0000000..77b08ed
--- /dev/null
+++ b/vendor/gimli/src/read/value.rs
@@ -0,0 +1,1621 @@
+//! Definitions for values used in DWARF expressions.
+
+use crate::constants;
+#[cfg(feature = "read")]
+use crate::read::{AttributeValue, DebuggingInformationEntry};
+use crate::read::{Error, Reader, Result};
+
+/// Convert a u64 to an i64, with sign extension if required.
+///
+/// This is primarily used when needing to treat `Value::Generic`
+/// as a signed value.
+#[inline]
+fn sign_extend(value: u64, mask: u64) -> i64 {
+    let value = (value & mask) as i64;
+    let sign = ((mask >> 1) + 1) as i64;
+    (value ^ sign).wrapping_sub(sign)
+}
+
+#[inline]
+fn mask_bit_size(addr_mask: u64) -> u32 {
+    64 - addr_mask.leading_zeros()
+}
+
+/// The type of an entry on the DWARF stack.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ValueType {
+    /// The generic type, which is address-sized and of unspecified sign,
+    /// as specified in the DWARF 5 standard, section 2.5.1.
+    /// This type is also used to represent address base types.
+    Generic,
+    /// Signed 8-bit integer type.
+    I8,
+    /// Unsigned 8-bit integer type.
+    U8,
+    /// Signed 16-bit integer type.
+    I16,
+    /// Unsigned 16-bit integer type.
+    U16,
+    /// Signed 32-bit integer type.
+    I32,
+    /// Unsigned 32-bit integer type.
+    U32,
+    /// Signed 64-bit integer type.
+    I64,
+    /// Unsigned 64-bit integer type.
+    U64,
+    /// 32-bit floating point type.
+    F32,
+    /// 64-bit floating point type.
+    F64,
+}
+
+/// The value of an entry on the DWARF stack.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Value {
+    /// A generic value, which is address-sized and of unspecified sign.
+    Generic(u64),
+    /// A signed 8-bit integer value.
+    I8(i8),
+    /// An unsigned 8-bit integer value.
+    U8(u8),
+    /// A signed 16-bit integer value.
+    I16(i16),
+    /// An unsigned 16-bit integer value.
+    U16(u16),
+    /// A signed 32-bit integer value.
+    I32(i32),
+    /// An unsigned 32-bit integer value.
+    U32(u32),
+    /// A signed 64-bit integer value.
+    I64(i64),
+    /// An unsigned 64-bit integer value.
+    U64(u64),
+    /// A 32-bit floating point value.
+    F32(f32),
+    /// A 64-bit floating point value.
+    F64(f64),
+}
+
+impl ValueType {
+    /// The size in bits of a value for this type.
+    pub fn bit_size(self, addr_mask: u64) -> u32 {
+        match self {
+            ValueType::Generic => mask_bit_size(addr_mask),
+            ValueType::I8 | ValueType::U8 => 8,
+            ValueType::I16 | ValueType::U16 => 16,
+            ValueType::I32 | ValueType::U32 | ValueType::F32 => 32,
+            ValueType::I64 | ValueType::U64 | ValueType::F64 => 64,
+        }
+    }
+
+    /// Construct a `ValueType` from the attributes of a base type DIE.
+    pub fn from_encoding(encoding: constants::DwAte, byte_size: u64) -> Option<ValueType> {
+        Some(match (encoding, byte_size) {
+            (constants::DW_ATE_signed, 1) => ValueType::I8,
+            (constants::DW_ATE_signed, 2) => ValueType::I16,
+            (constants::DW_ATE_signed, 4) => ValueType::I32,
+            (constants::DW_ATE_signed, 8) => ValueType::I64,
+            (constants::DW_ATE_unsigned, 1) => ValueType::U8,
+            (constants::DW_ATE_unsigned, 2) => ValueType::U16,
+            (constants::DW_ATE_unsigned, 4) => ValueType::U32,
+            (constants::DW_ATE_unsigned, 8) => ValueType::U64,
+            (constants::DW_ATE_float, 4) => ValueType::F32,
+            (constants::DW_ATE_float, 8) => ValueType::F64,
+            _ => return None,
+        })
+    }
+
+    /// Construct a `ValueType` from a base type DIE.
+    #[cfg(feature = "read")]
+    pub fn from_entry<R: Reader>(
+        entry: &DebuggingInformationEntry<R>,
+    ) -> Result<Option<ValueType>> {
+        if entry.tag() != constants::DW_TAG_base_type {
+            return Ok(None);
+        }
+        let mut encoding = None;
+        let mut byte_size = None;
+        let mut endianity = constants::DW_END_default;
+        let mut attrs = entry.attrs();
+        while let Some(attr) = attrs.next()? {
+            match attr.name() {
+                constants::DW_AT_byte_size => byte_size = attr.udata_value(),
+                constants::DW_AT_encoding => {
+                    if let AttributeValue::Encoding(x) = attr.value() {
+                        encoding = Some(x);
+                    }
+                }
+                constants::DW_AT_endianity => {
+                    if let AttributeValue::Endianity(x) = attr.value() {
+                        endianity = x;
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        if endianity != constants::DW_END_default {
+            // TODO: we could check if it matches the reader endianity,
+            // but normally it would use DW_END_default in that case.
+            return Ok(None);
+        }
+
+        if let (Some(encoding), Some(byte_size)) = (encoding, byte_size) {
+            Ok(ValueType::from_encoding(encoding, byte_size))
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+impl Value {
+    /// Return the `ValueType` corresponding to this `Value`.
+    pub fn value_type(&self) -> ValueType {
+        match *self {
+            Value::Generic(_) => ValueType::Generic,
+            Value::I8(_) => ValueType::I8,
+            Value::U8(_) => ValueType::U8,
+            Value::I16(_) => ValueType::I16,
+            Value::U16(_) => ValueType::U16,
+            Value::I32(_) => ValueType::I32,
+            Value::U32(_) => ValueType::U32,
+            Value::I64(_) => ValueType::I64,
+            Value::U64(_) => ValueType::U64,
+            Value::F32(_) => ValueType::F32,
+            Value::F64(_) => ValueType::F64,
+        }
+    }
+
+    /// Read a `Value` with the given `value_type` from a `Reader`.
+    pub fn parse<R: Reader>(value_type: ValueType, mut bytes: R) -> Result<Value> {
+        let value = match value_type {
+            ValueType::I8 => Value::I8(bytes.read_i8()?),
+            ValueType::U8 => Value::U8(bytes.read_u8()?),
+            ValueType::I16 => Value::I16(bytes.read_i16()?),
+            ValueType::U16 => Value::U16(bytes.read_u16()?),
+            ValueType::I32 => Value::I32(bytes.read_i32()?),
+            ValueType::U32 => Value::U32(bytes.read_u32()?),
+            ValueType::I64 => Value::I64(bytes.read_i64()?),
+            ValueType::U64 => Value::U64(bytes.read_u64()?),
+            ValueType::F32 => Value::F32(bytes.read_f32()?),
+            ValueType::F64 => Value::F64(bytes.read_f64()?),
+            _ => return Err(Error::UnsupportedTypeOperation),
+        };
+        Ok(value)
+    }
+
+    /// Convert a `Value` to a `u64`.
+    ///
+    /// The `ValueType` of `self` must be integral.
+    /// Values are sign extended if the source value is signed.
+    pub fn to_u64(self, addr_mask: u64) -> Result<u64> {
+        let value = match self {
+            Value::Generic(value) => value & addr_mask,
+            Value::I8(value) => value as u64,
+            Value::U8(value) => u64::from(value),
+            Value::I16(value) => value as u64,
+            Value::U16(value) => u64::from(value),
+            Value::I32(value) => value as u64,
+            Value::U32(value) => u64::from(value),
+            Value::I64(value) => value as u64,
+            Value::U64(value) => value as u64,
+            _ => return Err(Error::IntegralTypeRequired),
+        };
+        Ok(value)
+    }
+
+    /// Create a `Value` with the given `value_type` from a `u64` value.
+    ///
+    /// The `value_type` may be integral or floating point.
+    /// The result is truncated if the `u64` value does
+    /// not fit the bounds of the `value_type`.
+    pub fn from_u64(value_type: ValueType, value: u64) -> Result<Value> {
+        let value = match value_type {
+            ValueType::Generic => Value::Generic(value),
+            ValueType::I8 => Value::I8(value as i8),
+            ValueType::U8 => Value::U8(value as u8),
+            ValueType::I16 => Value::I16(value as i16),
+            ValueType::U16 => Value::U16(value as u16),
+            ValueType::I32 => Value::I32(value as i32),
+            ValueType::U32 => Value::U32(value as u32),
+            ValueType::I64 => Value::I64(value as i64),
+            ValueType::U64 => Value::U64(value),
+            ValueType::F32 => Value::F32(value as f32),
+            ValueType::F64 => Value::F64(value as f64),
+        };
+        Ok(value)
+    }
+
+    /// Create a `Value` with the given `value_type` from a `f32` value.
+    ///
+    /// The `value_type` may be integral or floating point.
+    /// The result is not defined if the `f32` value does
+    /// not fit the bounds of the `value_type`.
+    fn from_f32(value_type: ValueType, value: f32) -> Result<Value> {
+        let value = match value_type {
+            ValueType::Generic => Value::Generic(value as u64),
+            ValueType::I8 => Value::I8(value as i8),
+            ValueType::U8 => Value::U8(value as u8),
+            ValueType::I16 => Value::I16(value as i16),
+            ValueType::U16 => Value::U16(value as u16),
+            ValueType::I32 => Value::I32(value as i32),
+            ValueType::U32 => Value::U32(value as u32),
+            ValueType::I64 => Value::I64(value as i64),
+            ValueType::U64 => Value::U64(value as u64),
+            ValueType::F32 => Value::F32(value),
+            ValueType::F64 => Value::F64(f64::from(value)),
+        };
+        Ok(value)
+    }
+
+    /// Create a `Value` with the given `value_type` from a `f64` value.
+    ///
+    /// The `value_type` may be integral or floating point.
+    /// The result is not defined if the `f64` value does
+    /// not fit the bounds of the `value_type`.
+    fn from_f64(value_type: ValueType, value: f64) -> Result<Value> {
+        let value = match value_type {
+            ValueType::Generic => Value::Generic(value as u64),
+            ValueType::I8 => Value::I8(value as i8),
+            ValueType::U8 => Value::U8(value as u8),
+            ValueType::I16 => Value::I16(value as i16),
+            ValueType::U16 => Value::U16(value as u16),
+            ValueType::I32 => Value::I32(value as i32),
+            ValueType::U32 => Value::U32(value as u32),
+            ValueType::I64 => Value::I64(value as i64),
+            ValueType::U64 => Value::U64(value as u64),
+            ValueType::F32 => Value::F32(value as f32),
+            ValueType::F64 => Value::F64(value),
+        };
+        Ok(value)
+    }
+
+    /// Convert a `Value` to the given `value_type`.
+    ///
+    /// When converting between integral types, the result is truncated
+    /// if the source value does not fit the bounds of the `value_type`.
+    /// When converting from floating point types, the result is not defined
+    /// if the source value does not fit the bounds of the `value_type`.
+    ///
+    /// This corresponds to the DWARF `DW_OP_convert` operation.
+    pub fn convert(self, value_type: ValueType, addr_mask: u64) -> Result<Value> {
+        match self {
+            Value::F32(value) => Value::from_f32(value_type, value),
+            Value::F64(value) => Value::from_f64(value_type, value),
+            _ => Value::from_u64(value_type, self.to_u64(addr_mask)?),
+        }
+    }
+
+    /// Reinterpret the bits in a `Value` as the given `value_type`.
+    ///
+    /// The source and result value types must have equal sizes.
+    ///
+    /// This corresponds to the DWARF `DW_OP_reinterpret` operation.
+    pub fn reinterpret(self, value_type: ValueType, addr_mask: u64) -> Result<Value> {
+        if self.value_type().bit_size(addr_mask) != value_type.bit_size(addr_mask) {
+            return Err(Error::TypeMismatch);
+        }
+        let bits = match self {
+            Value::Generic(value) => value,
+            Value::I8(value) => value as u64,
+            Value::U8(value) => u64::from(value),
+            Value::I16(value) => value as u64,
+            Value::U16(value) => u64::from(value),
+            Value::I32(value) => value as u64,
+            Value::U32(value) => u64::from(value),
+            Value::I64(value) => value as u64,
+            Value::U64(value) => value,
+            Value::F32(value) => u64::from(f32::to_bits(value)),
+            Value::F64(value) => f64::to_bits(value),
+        };
+        let value = match value_type {
+            ValueType::Generic => Value::Generic(bits),
+            ValueType::I8 => Value::I8(bits as i8),
+            ValueType::U8 => Value::U8(bits as u8),
+            ValueType::I16 => Value::I16(bits as i16),
+            ValueType::U16 => Value::U16(bits as u16),
+            ValueType::I32 => Value::I32(bits as i32),
+            ValueType::U32 => Value::U32(bits as u32),
+            ValueType::I64 => Value::I64(bits as i64),
+            ValueType::U64 => Value::U64(bits),
+            ValueType::F32 => Value::F32(f32::from_bits(bits as u32)),
+            ValueType::F64 => Value::F64(f64::from_bits(bits)),
+        };
+        Ok(value)
+    }
+
+    /// Perform an absolute value operation.
+    ///
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_abs` operation.
+    pub fn abs(self, addr_mask: u64) -> Result<Value> {
+        // wrapping_abs() can be used because DWARF specifies that the result is undefined
+        // for negative minimal values.
+        let value = match self {
+            Value::Generic(value) => {
+                Value::Generic(sign_extend(value, addr_mask).wrapping_abs() as u64)
+            }
+            Value::I8(value) => Value::I8(value.wrapping_abs()),
+            Value::I16(value) => Value::I16(value.wrapping_abs()),
+            Value::I32(value) => Value::I32(value.wrapping_abs()),
+            Value::I64(value) => Value::I64(value.wrapping_abs()),
+            // f32/f64::abs() is not available in libcore
+            Value::F32(value) => Value::F32(if value < 0. { -value } else { value }),
+            Value::F64(value) => Value::F64(if value < 0. { -value } else { value }),
+            Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => self,
+        };
+        Ok(value)
+    }
+
+    /// Perform a negation operation.
+    ///
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_neg` operation.
+    pub fn neg(self, addr_mask: u64) -> Result<Value> {
+        // wrapping_neg() can be used because DWARF specifies that the result is undefined
+        // for negative minimal values.
+        let value = match self {
+            Value::Generic(value) => {
+                Value::Generic(sign_extend(value, addr_mask).wrapping_neg() as u64)
+            }
+            Value::I8(value) => Value::I8(value.wrapping_neg()),
+            Value::I16(value) => Value::I16(value.wrapping_neg()),
+            Value::I32(value) => Value::I32(value.wrapping_neg()),
+            Value::I64(value) => Value::I64(value.wrapping_neg()),
+            Value::F32(value) => Value::F32(-value),
+            Value::F64(value) => Value::F64(-value),
+            // It's unclear if these should implicitly convert to a signed value.
+            // For now, we don't support them.
+            Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => {
+                return Err(Error::UnsupportedTypeOperation);
+            }
+        };
+        Ok(value)
+    }
+
+    /// Perform an addition operation.
+    ///
+    /// This operation requires matching types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_plus` operation.
+    pub fn add(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                Value::Generic(v1.wrapping_add(v2) & addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_add(v2)),
+            (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_add(v2)),
+            (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_add(v2)),
+            (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_add(v2)),
+            (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_add(v2)),
+            (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_add(v2)),
+            (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_add(v2)),
+            (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_add(v2)),
+            (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 + v2),
+            (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 + v2),
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(value)
+    }
+
+    /// Perform a subtraction operation.
+    ///
+    /// This operation requires matching types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_minus` operation.
+    pub fn sub(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                Value::Generic(v1.wrapping_sub(v2) & addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_sub(v2)),
+            (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_sub(v2)),
+            (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_sub(v2)),
+            (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_sub(v2)),
+            (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_sub(v2)),
+            (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_sub(v2)),
+            (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_sub(v2)),
+            (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_sub(v2)),
+            (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 - v2),
+            (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 - v2),
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(value)
+    }
+
+    /// Perform a multiplication operation.
+    ///
+    /// This operation requires matching types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_mul` operation.
+    pub fn mul(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                Value::Generic(v1.wrapping_mul(v2) & addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_mul(v2)),
+            (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_mul(v2)),
+            (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_mul(v2)),
+            (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_mul(v2)),
+            (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_mul(v2)),
+            (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_mul(v2)),
+            (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_mul(v2)),
+            (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_mul(v2)),
+            (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 * v2),
+            (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 * v2),
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(value)
+    }
+
+    /// Perform a division operation.
+    ///
+    /// This operation requires matching types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_div` operation.
+    pub fn div(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        match rhs {
+            Value::Generic(v2) if sign_extend(v2, addr_mask) == 0 => {
+                return Err(Error::DivisionByZero);
+            }
+            Value::I8(0)
+            | Value::U8(0)
+            | Value::I16(0)
+            | Value::U16(0)
+            | Value::I32(0)
+            | Value::U32(0)
+            | Value::I64(0)
+            | Value::U64(0) => {
+                return Err(Error::DivisionByZero);
+            }
+            _ => {}
+        }
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                // Signed division
+                Value::Generic(
+                    sign_extend(v1, addr_mask).wrapping_div(sign_extend(v2, addr_mask)) as u64,
+                )
+            }
+            (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_div(v2)),
+            (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_div(v2)),
+            (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_div(v2)),
+            (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_div(v2)),
+            (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_div(v2)),
+            (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_div(v2)),
+            (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_div(v2)),
+            (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_div(v2)),
+            (Value::F32(v1), Value::F32(v2)) => Value::F32(v1 / v2),
+            (Value::F64(v1), Value::F64(v2)) => Value::F64(v1 / v2),
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(value)
+    }
+
+    /// Perform a remainder operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as an unsigned value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_mod` operation.
+    pub fn rem(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        match rhs {
+            Value::Generic(rhs) if (rhs & addr_mask) == 0 => {
+                return Err(Error::DivisionByZero);
+            }
+            Value::I8(0)
+            | Value::U8(0)
+            | Value::I16(0)
+            | Value::U16(0)
+            | Value::I32(0)
+            | Value::U32(0)
+            | Value::I64(0)
+            | Value::U64(0) => {
+                return Err(Error::DivisionByZero);
+            }
+            _ => {}
+        }
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                // Unsigned modulus
+                Value::Generic((v1 & addr_mask).wrapping_rem(v2 & addr_mask))
+            }
+            (Value::I8(v1), Value::I8(v2)) => Value::I8(v1.wrapping_rem(v2)),
+            (Value::U8(v1), Value::U8(v2)) => Value::U8(v1.wrapping_rem(v2)),
+            (Value::I16(v1), Value::I16(v2)) => Value::I16(v1.wrapping_rem(v2)),
+            (Value::U16(v1), Value::U16(v2)) => Value::U16(v1.wrapping_rem(v2)),
+            (Value::I32(v1), Value::I32(v2)) => Value::I32(v1.wrapping_rem(v2)),
+            (Value::U32(v1), Value::U32(v2)) => Value::U32(v1.wrapping_rem(v2)),
+            (Value::I64(v1), Value::I64(v2)) => Value::I64(v1.wrapping_rem(v2)),
+            (Value::U64(v1), Value::U64(v2)) => Value::U64(v1.wrapping_rem(v2)),
+            (Value::F32(_), Value::F32(_)) => return Err(Error::IntegralTypeRequired),
+            (Value::F64(_), Value::F64(_)) => return Err(Error::IntegralTypeRequired),
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(value)
+    }
+
+    /// Perform a bitwise not operation.
+    ///
+    /// This operation requires matching integral types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_not` operation.
+    pub fn not(self, addr_mask: u64) -> Result<Value> {
+        let value_type = self.value_type();
+        let v = self.to_u64(addr_mask)?;
+        Value::from_u64(value_type, !v)
+    }
+
+    /// Perform a bitwise and operation.
+    ///
+    /// This operation requires matching integral types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_and` operation.
+    pub fn and(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value_type = self.value_type();
+        if value_type != rhs.value_type() {
+            return Err(Error::TypeMismatch);
+        }
+        let v1 = self.to_u64(addr_mask)?;
+        let v2 = rhs.to_u64(addr_mask)?;
+        Value::from_u64(value_type, v1 & v2)
+    }
+
+    /// Perform a bitwise or operation.
+    ///
+    /// This operation requires matching integral types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_or` operation.
+    pub fn or(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value_type = self.value_type();
+        if value_type != rhs.value_type() {
+            return Err(Error::TypeMismatch);
+        }
+        let v1 = self.to_u64(addr_mask)?;
+        let v2 = rhs.to_u64(addr_mask)?;
+        Value::from_u64(value_type, v1 | v2)
+    }
+
+    /// Perform a bitwise exclusive-or operation.
+    ///
+    /// This operation requires matching integral types.
+    ///
+    /// This corresponds to the DWARF `DW_OP_xor` operation.
+    pub fn xor(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value_type = self.value_type();
+        if value_type != rhs.value_type() {
+            return Err(Error::TypeMismatch);
+        }
+        let v1 = self.to_u64(addr_mask)?;
+        let v2 = rhs.to_u64(addr_mask)?;
+        Value::from_u64(value_type, v1 ^ v2)
+    }
+
+    /// Convert value to bit length suitable for a shift operation.
+    ///
+    /// If the value is negative then an error is returned.
+    fn shift_length(self) -> Result<u64> {
+        let value = match self {
+            Value::Generic(value) => value,
+            Value::I8(value) if value >= 0 => value as u64,
+            Value::U8(value) => u64::from(value),
+            Value::I16(value) if value >= 0 => value as u64,
+            Value::U16(value) => u64::from(value),
+            Value::I32(value) if value >= 0 => value as u64,
+            Value::U32(value) => u64::from(value),
+            Value::I64(value) if value >= 0 => value as u64,
+            Value::U64(value) => value,
+            _ => return Err(Error::InvalidShiftExpression),
+        };
+        Ok(value)
+    }
+
+    /// Perform a shift left operation.
+    ///
+    /// This operation requires integral types.
+    /// If the shift length exceeds the type size, then 0 is returned.
+    /// If the shift length is negative then an error is returned.
+    ///
+    /// This corresponds to the DWARF `DW_OP_shl` operation.
+    pub fn shl(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let v2 = rhs.shift_length()?;
+        let value = match self {
+            Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) {
+                0
+            } else {
+                (v1 & addr_mask) << v2
+            }),
+            Value::I8(v1) => Value::I8(if v2 >= 8 { 0 } else { v1 << v2 }),
+            Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 << v2 }),
+            Value::I16(v1) => Value::I16(if v2 >= 16 { 0 } else { v1 << v2 }),
+            Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 << v2 }),
+            Value::I32(v1) => Value::I32(if v2 >= 32 { 0 } else { v1 << v2 }),
+            Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 << v2 }),
+            Value::I64(v1) => Value::I64(if v2 >= 64 { 0 } else { v1 << v2 }),
+            Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 << v2 }),
+            _ => return Err(Error::IntegralTypeRequired),
+        };
+        Ok(value)
+    }
+
+    /// Perform a logical shift right operation.
+    ///
+    /// This operation requires an unsigned integral type for the value.
+    /// If the value type is `Generic`, then it is interpreted as an unsigned value.
+    ///
+    /// This operation requires an integral type for the shift length.
+    /// If the shift length exceeds the type size, then 0 is returned.
+    /// If the shift length is negative then an error is returned.
+    ///
+    /// This corresponds to the DWARF `DW_OP_shr` operation.
+    pub fn shr(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let v2 = rhs.shift_length()?;
+        let value = match self {
+            Value::Generic(v1) => Value::Generic(if v2 >= u64::from(mask_bit_size(addr_mask)) {
+                0
+            } else {
+                (v1 & addr_mask) >> v2
+            }),
+            Value::U8(v1) => Value::U8(if v2 >= 8 { 0 } else { v1 >> v2 }),
+            Value::U16(v1) => Value::U16(if v2 >= 16 { 0 } else { v1 >> v2 }),
+            Value::U32(v1) => Value::U32(if v2 >= 32 { 0 } else { v1 >> v2 }),
+            Value::U64(v1) => Value::U64(if v2 >= 64 { 0 } else { v1 >> v2 }),
+            // It's unclear if signed values should implicitly convert to an unsigned value.
+            // For now, we don't support them.
+            Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) => {
+                return Err(Error::UnsupportedTypeOperation);
+            }
+            _ => return Err(Error::IntegralTypeRequired),
+        };
+        Ok(value)
+    }
+
+    /// Perform an arithmetic shift right operation.
+    ///
+    /// This operation requires a signed integral type for the value.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This operation requires an integral type for the shift length.
+    /// If the shift length exceeds the type size, then 0 is returned for positive values,
+    /// and -1 is returned for negative values.
+    /// If the shift length is negative then an error is returned.
+    ///
+    /// This corresponds to the DWARF `DW_OP_shra` operation.
+    pub fn shra(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let v2 = rhs.shift_length()?;
+        let value = match self {
+            Value::Generic(v1) => {
+                let v1 = sign_extend(v1, addr_mask);
+                let value = if v2 >= u64::from(mask_bit_size(addr_mask)) {
+                    if v1 < 0 {
+                        !0
+                    } else {
+                        0
+                    }
+                } else {
+                    (v1 >> v2) as u64
+                };
+                Value::Generic(value)
+            }
+            Value::I8(v1) => Value::I8(if v2 >= 8 {
+                if v1 < 0 {
+                    !0
+                } else {
+                    0
+                }
+            } else {
+                v1 >> v2
+            }),
+            Value::I16(v1) => Value::I16(if v2 >= 16 {
+                if v1 < 0 {
+                    !0
+                } else {
+                    0
+                }
+            } else {
+                v1 >> v2
+            }),
+            Value::I32(v1) => Value::I32(if v2 >= 32 {
+                if v1 < 0 {
+                    !0
+                } else {
+                    0
+                }
+            } else {
+                v1 >> v2
+            }),
+            Value::I64(v1) => Value::I64(if v2 >= 64 {
+                if v1 < 0 {
+                    !0
+                } else {
+                    0
+                }
+            } else {
+                v1 >> v2
+            }),
+            // It's unclear if unsigned values should implicitly convert to a signed value.
+            // For now, we don't support them.
+            Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) => {
+                return Err(Error::UnsupportedTypeOperation);
+            }
+            _ => return Err(Error::IntegralTypeRequired),
+        };
+        Ok(value)
+    }
+
+    /// Perform the `==` relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_eq` operation.
+    pub fn eq(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) == sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 == v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 == v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 == v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 == v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 == v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 == v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 == v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 == v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 == v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 == v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+
+    /// Perform the `>=` relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_ge` operation.
+    pub fn ge(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) >= sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 >= v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 >= v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 >= v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 >= v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 >= v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 >= v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 >= v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 >= v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 >= v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 >= v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+
+    /// Perform the `>` relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_gt` operation.
+    pub fn gt(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) > sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 > v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 > v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 > v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 > v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 > v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 > v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 > v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 > v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 > v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 > v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+
+    /// Perform the `<= relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_le` operation.
+    pub fn le(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) <= sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 <= v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 <= v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 <= v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 <= v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 <= v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 <= v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 <= v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 <= v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 <= v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 <= v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+
+    /// Perform the `< relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_lt` operation.
+    pub fn lt(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) < sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 < v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 < v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 < v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 < v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 < v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 < v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 < v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 < v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 < v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 < v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+
+    /// Perform the `!= relational operation.
+    ///
+    /// This operation requires matching integral types.
+    /// If the value type is `Generic`, then it is interpreted as a signed value.
+    ///
+    /// This corresponds to the DWARF `DW_OP_ne` operation.
+    pub fn ne(self, rhs: Value, addr_mask: u64) -> Result<Value> {
+        let value = match (self, rhs) {
+            (Value::Generic(v1), Value::Generic(v2)) => {
+                sign_extend(v1, addr_mask) != sign_extend(v2, addr_mask)
+            }
+            (Value::I8(v1), Value::I8(v2)) => v1 != v2,
+            (Value::U8(v1), Value::U8(v2)) => v1 != v2,
+            (Value::I16(v1), Value::I16(v2)) => v1 != v2,
+            (Value::U16(v1), Value::U16(v2)) => v1 != v2,
+            (Value::I32(v1), Value::I32(v2)) => v1 != v2,
+            (Value::U32(v1), Value::U32(v2)) => v1 != v2,
+            (Value::I64(v1), Value::I64(v2)) => v1 != v2,
+            (Value::U64(v1), Value::U64(v2)) => v1 != v2,
+            (Value::F32(v1), Value::F32(v2)) => v1 != v2,
+            (Value::F64(v1), Value::F64(v2)) => v1 != v2,
+            _ => return Err(Error::TypeMismatch),
+        };
+        Ok(Value::Generic(value as u64))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::common::{DebugAbbrevOffset, DebugInfoOffset, Encoding, Format};
+    use crate::endianity::LittleEndian;
+    use crate::read::{
+        Abbreviation, AttributeSpecification, DebuggingInformationEntry, EndianSlice, UnitHeader,
+        UnitOffset, UnitType,
+    };
+
+    #[test]
+    #[rustfmt::skip]
+    fn valuetype_from_encoding() {
+        let encoding = Encoding {
+            format: Format::Dwarf32,
+            version: 4,
+            address_size: 4,
+        };
+        let unit = UnitHeader::new(
+            encoding,
+            7,
+            UnitType::Compilation,
+            DebugAbbrevOffset(0),
+            DebugInfoOffset(0).into(),
+            EndianSlice::new(&[], LittleEndian),
+        );
+
+        let abbrev = Abbreviation::new(
+            42,
+            constants::DW_TAG_base_type,
+            constants::DW_CHILDREN_no,
+            vec![
+                AttributeSpecification::new(
+                    constants::DW_AT_byte_size,
+                    constants::DW_FORM_udata,
+                    None,
+                ),
+                AttributeSpecification::new(
+                    constants::DW_AT_encoding,
+                    constants::DW_FORM_udata,
+                    None,
+                ),
+                AttributeSpecification::new(
+                    constants::DW_AT_endianity,
+                    constants::DW_FORM_udata,
+                    None,
+                ),
+            ].into(),
+        );
+
+        for &(attrs, result) in &[
+            ([0x01, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I8),
+            ([0x02, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I16),
+            ([0x04, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I32),
+            ([0x08, constants::DW_ATE_signed.0, constants::DW_END_default.0], ValueType::I64),
+            ([0x01, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U8),
+            ([0x02, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U16),
+            ([0x04, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U32),
+            ([0x08, constants::DW_ATE_unsigned.0, constants::DW_END_default.0], ValueType::U64),
+            ([0x04, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F32),
+            ([0x08, constants::DW_ATE_float.0, constants::DW_END_default.0], ValueType::F64),
+        ] {
+            let entry = DebuggingInformationEntry::new(
+                UnitOffset(0),
+                EndianSlice::new(&attrs, LittleEndian),
+                &abbrev,
+                &unit,
+            );
+            assert_eq!(ValueType::from_entry(&entry), Ok(Some(result)));
+        }
+
+        for attrs in &[
+            [0x03, constants::DW_ATE_signed.0, constants::DW_END_default.0],
+            [0x02, constants::DW_ATE_signed.0, constants::DW_END_big.0],
+        ] {
+            let entry = DebuggingInformationEntry::new(
+                UnitOffset(0),
+                EndianSlice::new(attrs, LittleEndian),
+                &abbrev,
+                &unit,
+            );
+            assert_eq!(ValueType::from_entry(&entry), Ok(None));
+        }
+    }
+
+    #[test]
+    fn value_convert() {
+        let addr_mask = !0 >> 32;
+        for &(v, t, result) in &[
+            (Value::Generic(1), ValueType::I8, Ok(Value::I8(1))),
+            (Value::I8(1), ValueType::U8, Ok(Value::U8(1))),
+            (Value::U8(1), ValueType::I16, Ok(Value::I16(1))),
+            (Value::I16(1), ValueType::U16, Ok(Value::U16(1))),
+            (Value::U16(1), ValueType::I32, Ok(Value::I32(1))),
+            (Value::I32(1), ValueType::U32, Ok(Value::U32(1))),
+            (Value::U32(1), ValueType::F32, Ok(Value::F32(1.))),
+            (Value::F32(1.), ValueType::I64, Ok(Value::I64(1))),
+            (Value::I64(1), ValueType::U64, Ok(Value::U64(1))),
+            (Value::U64(1), ValueType::F64, Ok(Value::F64(1.))),
+            (Value::F64(1.), ValueType::Generic, Ok(Value::Generic(1))),
+        ] {
+            assert_eq!(v.convert(t, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_reinterpret() {
+        let addr_mask = !0 >> 32;
+        for &(v, t, result) in &[
+            // 8-bit
+            (Value::I8(-1), ValueType::U8, Ok(Value::U8(0xff))),
+            (Value::U8(0xff), ValueType::I8, Ok(Value::I8(-1))),
+            // 16-bit
+            (Value::I16(1), ValueType::U16, Ok(Value::U16(1))),
+            (Value::U16(1), ValueType::I16, Ok(Value::I16(1))),
+            // 32-bit
+            (Value::Generic(1), ValueType::I32, Ok(Value::I32(1))),
+            (Value::I32(1), ValueType::U32, Ok(Value::U32(1))),
+            (Value::U32(0x3f80_0000), ValueType::F32, Ok(Value::F32(1.0))),
+            (Value::F32(1.0), ValueType::Generic, Ok(Value::Generic(0x3f80_0000))),
+            // Type mismatches
+            (Value::Generic(1), ValueType::U8, Err(Error::TypeMismatch)),
+            (Value::U8(1), ValueType::U16, Err(Error::TypeMismatch)),
+            (Value::U16(1), ValueType::U32, Err(Error::TypeMismatch)),
+            (Value::U32(1), ValueType::U64, Err(Error::TypeMismatch)),
+            (Value::U64(1), ValueType::Generic, Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v.reinterpret(t, addr_mask), result);
+        }
+
+        let addr_mask = !0;
+        for &(v, t, result) in &[
+            // 64-bit
+            (Value::Generic(1), ValueType::I64, Ok(Value::I64(1))),
+            (Value::I64(1), ValueType::U64, Ok(Value::U64(1))),
+            (Value::U64(0x3ff0_0000_0000_0000), ValueType::F64, Ok(Value::F64(1.0))),
+            (Value::F64(1.0), ValueType::Generic, Ok(Value::Generic(0x3ff0_0000_0000_0000))),
+        ] {
+            assert_eq!(v.reinterpret(t, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_abs() {
+        let addr_mask = 0xffff_ffff;
+        for &(v, result) in &[
+            (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))),
+            (Value::I8(-1), Ok(Value::I8(1))),
+            (Value::U8(1), Ok(Value::U8(1))),
+            (Value::I16(-1), Ok(Value::I16(1))),
+            (Value::U16(1), Ok(Value::U16(1))),
+            (Value::I32(-1), Ok(Value::I32(1))),
+            (Value::U32(1), Ok(Value::U32(1))),
+            (Value::I64(-1), Ok(Value::I64(1))),
+            (Value::U64(1), Ok(Value::U64(1))),
+            (Value::F32(-1.), Ok(Value::F32(1.))),
+            (Value::F64(-1.), Ok(Value::F64(1.))),
+        ] {
+            assert_eq!(v.abs(addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_neg() {
+        let addr_mask = 0xffff_ffff;
+        for &(v, result) in &[
+            (Value::Generic(0xffff_ffff), Ok(Value::Generic(1))),
+            (Value::I8(1), Ok(Value::I8(-1))),
+            (Value::U8(1), Err(Error::UnsupportedTypeOperation)),
+            (Value::I16(1), Ok(Value::I16(-1))),
+            (Value::U16(1), Err(Error::UnsupportedTypeOperation)),
+            (Value::I32(1), Ok(Value::I32(-1))),
+            (Value::U32(1), Err(Error::UnsupportedTypeOperation)),
+            (Value::I64(1), Ok(Value::I64(-1))),
+            (Value::U64(1), Err(Error::UnsupportedTypeOperation)),
+            (Value::F32(1.), Ok(Value::F32(-1.))),
+            (Value::F64(1.), Ok(Value::F64(-1.))),
+        ] {
+            assert_eq!(v.neg(addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_add() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(1), Value::Generic(2), Ok(Value::Generic(3))),
+            (Value::I8(-1), Value::I8(2), Ok(Value::I8(1))),
+            (Value::U8(1), Value::U8(2), Ok(Value::U8(3))),
+            (Value::I16(-1), Value::I16(2), Ok(Value::I16(1))),
+            (Value::U16(1), Value::U16(2), Ok(Value::U16(3))),
+            (Value::I32(-1), Value::I32(2), Ok(Value::I32(1))),
+            (Value::U32(1), Value::U32(2), Ok(Value::U32(3))),
+            (Value::I64(-1), Value::I64(2), Ok(Value::I64(1))),
+            (Value::U64(1), Value::U64(2), Ok(Value::U64(3))),
+            (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(1.))),
+            (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(1.))),
+            (Value::Generic(1), Value::U32(2), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.add(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_sub() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))),
+            (Value::I8(-1), Value::I8(2), Ok(Value::I8(-3))),
+            (Value::U8(3), Value::U8(2), Ok(Value::U8(1))),
+            (Value::I16(-1), Value::I16(2), Ok(Value::I16(-3))),
+            (Value::U16(3), Value::U16(2), Ok(Value::U16(1))),
+            (Value::I32(-1), Value::I32(2), Ok(Value::I32(-3))),
+            (Value::U32(3), Value::U32(2), Ok(Value::U32(1))),
+            (Value::I64(-1), Value::I64(2), Ok(Value::I64(-3))),
+            (Value::U64(3), Value::U64(2), Ok(Value::U64(1))),
+            (Value::F32(-1.), Value::F32(2.), Ok(Value::F32(-3.))),
+            (Value::F64(-1.), Value::F64(2.), Ok(Value::F64(-3.))),
+            (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.sub(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_mul() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(2), Value::Generic(3), Ok(Value::Generic(6))),
+            (Value::I8(-2), Value::I8(3), Ok(Value::I8(-6))),
+            (Value::U8(2), Value::U8(3), Ok(Value::U8(6))),
+            (Value::I16(-2), Value::I16(3), Ok(Value::I16(-6))),
+            (Value::U16(2), Value::U16(3), Ok(Value::U16(6))),
+            (Value::I32(-2), Value::I32(3), Ok(Value::I32(-6))),
+            (Value::U32(2), Value::U32(3), Ok(Value::U32(6))),
+            (Value::I64(-2), Value::I64(3), Ok(Value::I64(-6))),
+            (Value::U64(2), Value::U64(3), Ok(Value::U64(6))),
+            (Value::F32(-2.), Value::F32(3.), Ok(Value::F32(-6.))),
+            (Value::F64(-2.), Value::F64(3.), Ok(Value::F64(-6.))),
+            (Value::Generic(2), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.mul(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_div() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(6), Value::Generic(3), Ok(Value::Generic(2))),
+            (Value::I8(-6), Value::I8(3), Ok(Value::I8(-2))),
+            (Value::U8(6), Value::U8(3), Ok(Value::U8(2))),
+            (Value::I16(-6), Value::I16(3), Ok(Value::I16(-2))),
+            (Value::U16(6), Value::U16(3), Ok(Value::U16(2))),
+            (Value::I32(-6), Value::I32(3), Ok(Value::I32(-2))),
+            (Value::U32(6), Value::U32(3), Ok(Value::U32(2))),
+            (Value::I64(-6), Value::I64(3), Ok(Value::I64(-2))),
+            (Value::U64(6), Value::U64(3), Ok(Value::U64(2))),
+            (Value::F32(-6.), Value::F32(3.), Ok(Value::F32(-2.))),
+            (Value::F64(-6.), Value::F64(3.), Ok(Value::F64(-2.))),
+            (Value::Generic(6), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.div(v2, addr_mask), result);
+        }
+        for &(v1, v2, result) in &[
+            (Value::Generic(6), Value::Generic(0), Err(Error::DivisionByZero)),
+            (Value::I8(-6), Value::I8(0), Err(Error::DivisionByZero)),
+            (Value::U8(6), Value::U8(0), Err(Error::DivisionByZero)),
+            (Value::I16(-6), Value::I16(0), Err(Error::DivisionByZero)),
+            (Value::U16(6), Value::U16(0), Err(Error::DivisionByZero)),
+            (Value::I32(-6), Value::I32(0), Err(Error::DivisionByZero)),
+            (Value::U32(6), Value::U32(0), Err(Error::DivisionByZero)),
+            (Value::I64(-6), Value::I64(0), Err(Error::DivisionByZero)),
+            (Value::U64(6), Value::U64(0), Err(Error::DivisionByZero)),
+            (Value::F32(-6.), Value::F32(0.), Ok(Value::F32(-6. / 0.))),
+            (Value::F64(-6.), Value::F64(0.), Ok(Value::F64(-6. / 0.))),
+        ] {
+            assert_eq!(v1.div(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_rem() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(2), Ok(Value::Generic(1))),
+            (Value::I8(-3), Value::I8(2), Ok(Value::I8(-1))),
+            (Value::U8(3), Value::U8(2), Ok(Value::U8(1))),
+            (Value::I16(-3), Value::I16(2), Ok(Value::I16(-1))),
+            (Value::U16(3), Value::U16(2), Ok(Value::U16(1))),
+            (Value::I32(-3), Value::I32(2), Ok(Value::I32(-1))),
+            (Value::U32(3), Value::U32(2), Ok(Value::U32(1))),
+            (Value::I64(-3), Value::I64(2), Ok(Value::I64(-1))),
+            (Value::U64(3), Value::U64(2), Ok(Value::U64(1))),
+            (Value::F32(-3.), Value::F32(2.), Err(Error::IntegralTypeRequired)),
+            (Value::F64(-3.), Value::F64(2.), Err(Error::IntegralTypeRequired)),
+            (Value::Generic(3), Value::U32(2), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.rem(v2, addr_mask), result);
+        }
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(0), Err(Error::DivisionByZero)),
+            (Value::I8(-3), Value::I8(0), Err(Error::DivisionByZero)),
+            (Value::U8(3), Value::U8(0), Err(Error::DivisionByZero)),
+            (Value::I16(-3), Value::I16(0), Err(Error::DivisionByZero)),
+            (Value::U16(3), Value::U16(0), Err(Error::DivisionByZero)),
+            (Value::I32(-3), Value::I32(0), Err(Error::DivisionByZero)),
+            (Value::U32(3), Value::U32(0), Err(Error::DivisionByZero)),
+            (Value::I64(-3), Value::I64(0), Err(Error::DivisionByZero)),
+            (Value::U64(3), Value::U64(0), Err(Error::DivisionByZero)),
+        ] {
+            assert_eq!(v1.rem(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_not() {
+        let addr_mask = 0xffff_ffff;
+        for &(v, result) in &[
+            (Value::Generic(1), Ok(Value::Generic(!1))),
+            (Value::I8(1), Ok(Value::I8(!1))),
+            (Value::U8(1), Ok(Value::U8(!1))),
+            (Value::I16(1), Ok(Value::I16(!1))),
+            (Value::U16(1), Ok(Value::U16(!1))),
+            (Value::I32(1), Ok(Value::I32(!1))),
+            (Value::U32(1), Ok(Value::U32(!1))),
+            (Value::I64(1), Ok(Value::I64(!1))),
+            (Value::U64(1), Ok(Value::U64(!1))),
+            (Value::F32(1.), Err(Error::IntegralTypeRequired)),
+            (Value::F64(1.), Err(Error::IntegralTypeRequired)),
+        ] {
+            assert_eq!(v.not(addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_and() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(1))),
+            (Value::I8(3), Value::I8(5), Ok(Value::I8(1))),
+            (Value::U8(3), Value::U8(5), Ok(Value::U8(1))),
+            (Value::I16(3), Value::I16(5), Ok(Value::I16(1))),
+            (Value::U16(3), Value::U16(5), Ok(Value::U16(1))),
+            (Value::I32(3), Value::I32(5), Ok(Value::I32(1))),
+            (Value::U32(3), Value::U32(5), Ok(Value::U32(1))),
+            (Value::I64(3), Value::I64(5), Ok(Value::I64(1))),
+            (Value::U64(3), Value::U64(5), Ok(Value::U64(1))),
+            (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
+            (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
+            (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.and(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_or() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(7))),
+            (Value::I8(3), Value::I8(5), Ok(Value::I8(7))),
+            (Value::U8(3), Value::U8(5), Ok(Value::U8(7))),
+            (Value::I16(3), Value::I16(5), Ok(Value::I16(7))),
+            (Value::U16(3), Value::U16(5), Ok(Value::U16(7))),
+            (Value::I32(3), Value::I32(5), Ok(Value::I32(7))),
+            (Value::U32(3), Value::U32(5), Ok(Value::U32(7))),
+            (Value::I64(3), Value::I64(5), Ok(Value::I64(7))),
+            (Value::U64(3), Value::U64(5), Ok(Value::U64(7))),
+            (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
+            (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
+            (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.or(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_xor() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(6))),
+            (Value::I8(3), Value::I8(5), Ok(Value::I8(6))),
+            (Value::U8(3), Value::U8(5), Ok(Value::U8(6))),
+            (Value::I16(3), Value::I16(5), Ok(Value::I16(6))),
+            (Value::U16(3), Value::U16(5), Ok(Value::U16(6))),
+            (Value::I32(3), Value::I32(5), Ok(Value::I32(6))),
+            (Value::U32(3), Value::U32(5), Ok(Value::U32(6))),
+            (Value::I64(3), Value::I64(5), Ok(Value::I64(6))),
+            (Value::U64(3), Value::U64(5), Ok(Value::U64(6))),
+            (Value::F32(3.), Value::F32(5.), Err(Error::IntegralTypeRequired)),
+            (Value::F64(3.), Value::F64(5.), Err(Error::IntegralTypeRequired)),
+            (Value::Generic(3), Value::U32(5), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.xor(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_shl() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            // One of each type
+            (Value::Generic(3), Value::Generic(5), Ok(Value::Generic(96))),
+            (Value::I8(3), Value::U8(5), Ok(Value::I8(96))),
+            (Value::U8(3), Value::I8(5), Ok(Value::U8(96))),
+            (Value::I16(3), Value::U16(5), Ok(Value::I16(96))),
+            (Value::U16(3), Value::I16(5), Ok(Value::U16(96))),
+            (Value::I32(3), Value::U32(5), Ok(Value::I32(96))),
+            (Value::U32(3), Value::I32(5), Ok(Value::U32(96))),
+            (Value::I64(3), Value::U64(5), Ok(Value::I64(96))),
+            (Value::U64(3), Value::I64(5), Ok(Value::U64(96))),
+            (Value::F32(3.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            (Value::F64(3.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            // Invalid shifts
+            (Value::U8(3), Value::I8(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(3), Value::I16(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(3), Value::I32(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(3), Value::I64(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(3), Value::F32(5.), Err(Error::InvalidShiftExpression)),
+            (Value::U8(3), Value::F64(5.), Err(Error::InvalidShiftExpression)),
+            // Large shifts
+            (Value::Generic(3), Value::Generic(32), Ok(Value::Generic(0))),
+            (Value::I8(3), Value::U8(8), Ok(Value::I8(0))),
+            (Value::U8(3), Value::I8(9), Ok(Value::U8(0))),
+            (Value::I16(3), Value::U16(17), Ok(Value::I16(0))),
+            (Value::U16(3), Value::I16(16), Ok(Value::U16(0))),
+            (Value::I32(3), Value::U32(32), Ok(Value::I32(0))),
+            (Value::U32(3), Value::I32(33), Ok(Value::U32(0))),
+            (Value::I64(3), Value::U64(65), Ok(Value::I64(0))),
+            (Value::U64(3), Value::I64(64), Ok(Value::U64(0))),
+        ] {
+            assert_eq!(v1.shl(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_shr() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            // One of each type
+            (Value::Generic(96), Value::Generic(5), Ok(Value::Generic(3))),
+            (Value::I8(96), Value::U8(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::U8(96), Value::I8(5), Ok(Value::U8(3))),
+            (Value::I16(96), Value::U16(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::U16(96), Value::I16(5), Ok(Value::U16(3))),
+            (Value::I32(96), Value::U32(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::U32(96), Value::I32(5), Ok(Value::U32(3))),
+            (Value::I64(96), Value::U64(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::U64(96), Value::I64(5), Ok(Value::U64(3))),
+            (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            // Invalid shifts
+            (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)),
+            // Large shifts
+            (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))),
+            (Value::U8(96), Value::I8(9), Ok(Value::U8(0))),
+            (Value::U16(96), Value::I16(16), Ok(Value::U16(0))),
+            (Value::U32(96), Value::I32(33), Ok(Value::U32(0))),
+            (Value::U64(96), Value::I64(64), Ok(Value::U64(0))),
+        ] {
+            assert_eq!(v1.shr(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn value_shra() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            // One of each type
+            (Value::Generic(u64::from(-96i32 as u32)), Value::Generic(5), Ok(Value::Generic(-3i64 as u64))),
+            (Value::I8(-96), Value::U8(5), Ok(Value::I8(-3))),
+            (Value::U8(96), Value::I8(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::I16(-96), Value::U16(5), Ok(Value::I16(-3))),
+            (Value::U16(96), Value::I16(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::I32(-96), Value::U32(5), Ok(Value::I32(-3))),
+            (Value::U32(96), Value::I32(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::I64(-96), Value::U64(5), Ok(Value::I64(-3))),
+            (Value::U64(96), Value::I64(5), Err(Error::UnsupportedTypeOperation)),
+            (Value::F32(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            (Value::F64(96.), Value::U8(5), Err(Error::IntegralTypeRequired)),
+            // Invalid shifts
+            (Value::U8(96), Value::I8(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I16(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I32(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::I64(-5), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::F32(5.), Err(Error::InvalidShiftExpression)),
+            (Value::U8(96), Value::F64(5.), Err(Error::InvalidShiftExpression)),
+            // Large shifts
+            (Value::Generic(96), Value::Generic(32), Ok(Value::Generic(0))),
+            (Value::I8(96), Value::U8(8), Ok(Value::I8(0))),
+            (Value::I8(-96), Value::U8(8), Ok(Value::I8(-1))),
+            (Value::I16(96), Value::U16(17), Ok(Value::I16(0))),
+            (Value::I16(-96), Value::U16(17), Ok(Value::I16(-1))),
+            (Value::I32(96), Value::U32(32), Ok(Value::I32(0))),
+            (Value::I32(-96), Value::U32(32), Ok(Value::I32(-1))),
+            (Value::I64(96), Value::U64(65), Ok(Value::I64(0))),
+            (Value::I64(-96), Value::U64(65), Ok(Value::I64(-1))),
+        ] {
+            assert_eq!(v1.shra(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_eq() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(1))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
+            (Value::I8(3), Value::I8(3), Ok(Value::Generic(1))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
+            (Value::U8(3), Value::U8(3), Ok(Value::Generic(1))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
+            (Value::I16(3), Value::I16(3), Ok(Value::Generic(1))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
+            (Value::U16(3), Value::U16(3), Ok(Value::Generic(1))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
+            (Value::I32(3), Value::I32(3), Ok(Value::Generic(1))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
+            (Value::U32(3), Value::U32(3), Ok(Value::Generic(1))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
+            (Value::I64(3), Value::I64(3), Ok(Value::Generic(1))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
+            (Value::U64(3), Value::U64(3), Ok(Value::Generic(1))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
+            (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(1))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
+            (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(1))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.eq(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_ne() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(3), Ok(Value::Generic(0))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
+            (Value::I8(3), Value::I8(3), Ok(Value::Generic(0))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
+            (Value::U8(3), Value::U8(3), Ok(Value::Generic(0))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
+            (Value::I16(3), Value::I16(3), Ok(Value::Generic(0))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
+            (Value::U16(3), Value::U16(3), Ok(Value::Generic(0))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
+            (Value::I32(3), Value::I32(3), Ok(Value::Generic(0))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
+            (Value::U32(3), Value::U32(3), Ok(Value::Generic(0))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
+            (Value::I64(3), Value::I64(3), Ok(Value::Generic(0))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
+            (Value::U64(3), Value::U64(3), Ok(Value::Generic(0))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
+            (Value::F32(3.), Value::F32(3.), Ok(Value::Generic(0))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
+            (Value::F64(3.), Value::F64(3.), Ok(Value::Generic(0))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.ne(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_ge() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
+            (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
+            (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
+            (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
+            (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
+            (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
+            (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
+            (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
+            (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
+            (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
+            (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.ge(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_gt() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(1))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(0))),
+            (Value::I8(3), Value::I8(!3), Ok(Value::Generic(1))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(0))),
+            (Value::U8(3), Value::U8(!3), Ok(Value::Generic(0))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(1))),
+            (Value::I16(3), Value::I16(!3), Ok(Value::Generic(1))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(0))),
+            (Value::U16(3), Value::U16(!3), Ok(Value::Generic(0))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(1))),
+            (Value::I32(3), Value::I32(!3), Ok(Value::Generic(1))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(0))),
+            (Value::U32(3), Value::U32(!3), Ok(Value::Generic(0))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(1))),
+            (Value::I64(3), Value::I64(!3), Ok(Value::Generic(1))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(0))),
+            (Value::U64(3), Value::U64(!3), Ok(Value::Generic(0))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(1))),
+            (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(1))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(0))),
+            (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(1))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(0))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.gt(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_le() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
+            (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
+            (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
+            (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
+            (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
+            (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
+            (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
+            (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
+            (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
+            (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
+            (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.le(v2, addr_mask), result);
+        }
+    }
+
+    #[test]
+    fn value_lt() {
+        let addr_mask = 0xffff_ffff;
+        for &(v1, v2, result) in &[
+            (Value::Generic(3), Value::Generic(!3), Ok(Value::Generic(0))),
+            (Value::Generic(!3), Value::Generic(3), Ok(Value::Generic(1))),
+            (Value::I8(3), Value::I8(!3), Ok(Value::Generic(0))),
+            (Value::I8(!3), Value::I8(3), Ok(Value::Generic(1))),
+            (Value::U8(3), Value::U8(!3), Ok(Value::Generic(1))),
+            (Value::U8(!3), Value::U8(3), Ok(Value::Generic(0))),
+            (Value::I16(3), Value::I16(!3), Ok(Value::Generic(0))),
+            (Value::I16(!3), Value::I16(3), Ok(Value::Generic(1))),
+            (Value::U16(3), Value::U16(!3), Ok(Value::Generic(1))),
+            (Value::U16(!3), Value::U16(3), Ok(Value::Generic(0))),
+            (Value::I32(3), Value::I32(!3), Ok(Value::Generic(0))),
+            (Value::I32(!3), Value::I32(3), Ok(Value::Generic(1))),
+            (Value::U32(3), Value::U32(!3), Ok(Value::Generic(1))),
+            (Value::U32(!3), Value::U32(3), Ok(Value::Generic(0))),
+            (Value::I64(3), Value::I64(!3), Ok(Value::Generic(0))),
+            (Value::I64(!3), Value::I64(3), Ok(Value::Generic(1))),
+            (Value::U64(3), Value::U64(!3), Ok(Value::Generic(1))),
+            (Value::U64(!3), Value::U64(3), Ok(Value::Generic(0))),
+            (Value::F32(3.), Value::F32(-3.), Ok(Value::Generic(0))),
+            (Value::F32(-3.), Value::F32(3.), Ok(Value::Generic(1))),
+            (Value::F64(3.), Value::F64(-3.), Ok(Value::Generic(0))),
+            (Value::F64(-3.), Value::F64(3.), Ok(Value::Generic(1))),
+            (Value::Generic(3), Value::U32(3), Err(Error::TypeMismatch)),
+        ] {
+            assert_eq!(v1.lt(v2, addr_mask), result);
+        }
+    }
+}
-- 
cgit v1.2.3