From a32069d31860a83a6ac64a7e045e97fa605317df Mon Sep 17 00:00:00 2001 From: Sam Thomas Date: Fri, 17 May 2024 01:59:46 +0100 Subject: [PATCH] refactor to represent bits as u32; remove superfluous ILs --- fugue-bv/src/core_bigint/mask_table.rs | 4 +- fugue-bv/src/core_bigint/mod.rs | 69 +- fugue-bv/src/core_mixed.rs | 41 +- fugue-bv/src/core_u64.rs | 63 +- fugue-core/src/eval/dummy.rs | 2 +- fugue-core/src/eval/fixed_state.rs | 4 +- fugue-core/src/eval/mod.rs | 18 +- fugue-core/src/lifter.rs | 2 +- fugue-fp/src/lib.rs | 8 +- fugue-ir/src/disassembly/lift.rs | 85 +- fugue-ir/src/disassembly/varnodedata.rs | 12 +- fugue-ir/src/il/ecode/mod.rs | 3853 ----------------------- fugue-ir/src/il/mod.rs | 8 - fugue-ir/src/il/pcode/mod.rs | 832 ----- fugue-ir/src/il/pcode/operand.rs | 274 -- fugue-ir/src/il/pcode/register.rs | 47 - fugue-ir/src/il/traits/mod.rs | 10 +- fugue-ir/src/lib.rs | 1 - fugue-ir/src/translator.rs | 239 +- fugue-state/src/pcode.rs | 220 +- fugue-state/src/register.rs | 110 +- fugue-state/src/traits.rs | 42 +- 22 files changed, 370 insertions(+), 5574 deletions(-) delete mode 100644 fugue-ir/src/il/ecode/mod.rs delete mode 100644 fugue-ir/src/il/pcode/mod.rs delete mode 100644 fugue-ir/src/il/pcode/operand.rs delete mode 100644 fugue-ir/src/il/pcode/register.rs diff --git a/fugue-bv/src/core_bigint/mask_table.rs b/fugue-bv/src/core_bigint/mask_table.rs index daa6d1f..ac732ca 100644 --- a/fugue-bv/src/core_bigint/mask_table.rs +++ b/fugue-bv/src/core_bigint/mask_table.rs @@ -2060,8 +2060,8 @@ fn mask_value(bits: u32) -> BigInt { } #[inline(always)] -pub(crate) fn lookup_mask(bits: usize) -> &'static BigInt { +pub(crate) fn lookup_mask(bits: u32) -> &'static BigInt { assert!(bits <= 2048, "unsupported BitVec size: {bits}"); - &MASK_TABLE[bits] + &MASK_TABLE[bits as usize] } diff --git a/fugue-bv/src/core_bigint/mod.rs b/fugue-bv/src/core_bigint/mod.rs index 830537f..18ff3f0 100644 --- a/fugue-bv/src/core_bigint/mod.rs +++ b/fugue-bv/src/core_bigint/mod.rs @@ -62,7 +62,7 @@ impl FromStr for BitVec { } .map_err(|_| ParseError::InvalidConst)?; - let bits = usize::from_str(sz).map_err(|_| ParseError::InvalidSize)?; + let bits = u32::from_str(sz).map_err(|_| ParseError::InvalidSize)?; Ok(Self::from_bigint(val, bits)) } @@ -74,11 +74,11 @@ impl BitVec { (bits << 1) | (sign as u32) } - fn set_bits(&mut self, bits: usize) { + fn set_bits(&mut self, bits: u32) { self.1 = ((bits as u32) << 1) | (self.1 & 1); } - pub fn from_bigint(v: BigInt, bits: usize) -> Self { + pub fn from_bigint(v: BigInt, bits: u32) -> Self { Self(Box::new(v), Self::pack_meta(false, bits as u32)).mask() } @@ -112,7 +112,7 @@ impl BitVec { } } - pub fn zero(bits: usize) -> Self { + pub fn zero(bits: u32) -> Self { if bits == 0 { //|| bits % 8 != 0 { panic!("bits must be > 0") @@ -121,7 +121,7 @@ impl BitVec { Self::from_bigint(BigInt::from(0), bits) } - pub fn one(bits: usize) -> Self { + pub fn one(bits: u32) -> Self { if bits == 0 { //|| bits % 8 != 0 { panic!("bits must be > 0") @@ -158,8 +158,8 @@ impl BitVec { lz } - pub fn bits(&self) -> usize { - (self.1 >> 1) as usize + pub fn bits(&self) -> u32 { + (self.1 >> 1) as u32 } pub fn signed(self) -> Self { @@ -223,12 +223,17 @@ impl BitVec { self.0.get_bit(0) } + pub fn bytes(&self) -> usize { + let bits = self.bits() as usize; + bits / 8 + if bits % 8 == 0 { 0 } else { 1 } + } + pub fn from_be_bytes(buf: &[u8]) -> Self { - Self::from_bigint(BigInt::from_digits(&buf, BVOrder::MsfBe), buf.len() * 8) + Self::from_bigint(BigInt::from_digits(&buf, BVOrder::MsfBe), buf.len() as u32 * 8) } pub fn from_le_bytes(buf: &[u8]) -> Self { - Self::from_bigint(BigInt::from_digits(&buf, BVOrder::LsfLe), buf.len() * 8) + Self::from_bigint(BigInt::from_digits(&buf, BVOrder::LsfLe), buf.len() as u32 * 8) } #[inline(always)] @@ -241,7 +246,8 @@ impl BitVec { } pub fn to_be_bytes(&self, buf: &mut [u8]) { - let size = self.bits() / 8 + if self.bits() % 8 == 0 { 0 } else { 1 }; + let bits = self.bits() as usize; + let size = bits / 8 + if bits % 8 == 0 { 0 } else { 1 }; if buf.len() != size { panic!("invalid buf size {}; expected {}", buf.len(), size); } @@ -252,13 +258,14 @@ impl BitVec { }; self.0.write_digits( - &mut buf[((self.bits() / 8) - self.0.significant_digits::())..], + &mut buf[(bits / 8 - self.0.significant_digits::())..], BVOrder::MsfBe, ); } pub fn to_le_bytes(&self, buf: &mut [u8]) { - let size = self.bits() / 8 + if self.bits() % 8 == 0 { 0 } else { 1 }; + let bits = self.bits() as usize; + let size = bits / 8 + if bits % 8 == 0 { 0 } else { 1 }; if buf.len() != size { panic!("invalid buf size {}; expected {}", buf.len(), size); } @@ -458,7 +465,7 @@ impl BitVec { ) } - pub fn max_value_with(bits: usize, signed: bool) -> Self { + pub fn max_value_with(bits: u32, signed: bool) -> Self { let mask = lookup_mask(bits); if signed { Self::from_bigint_with( @@ -486,7 +493,7 @@ impl BitVec { } } - pub fn min_value_with(bits: usize, signed: bool) -> Self { + pub fn min_value_with(bits: u32, signed: bool) -> Self { let mask = lookup_mask(bits); if signed { Self::from_bigint_with(-(BigInt::from(1) << (bits - 1) as u32), mask).signed() @@ -503,25 +510,25 @@ impl BitVec { } } - pub fn signed_cast(&self, size: usize) -> Self { + pub fn signed_cast(&self, size: u32) -> Self { self.clone().signed().cast(size) } - pub fn unsigned_cast(&self, size: usize) -> Self { + pub fn unsigned_cast(&self, size: u32) -> Self { self.clone().unsigned().cast(size) } - pub fn signed_cast_assign(&mut self, size: usize) { + pub fn signed_cast_assign(&mut self, size: u32) { self.signed_assign(); self.cast_assign(size) } - pub fn unsigned_cast_assign(&mut self, size: usize) { + pub fn unsigned_cast_assign(&mut self, size: u32) { self.unsigned_assign(); self.cast_assign(size) } - pub fn cast(self, size: usize) -> Self { + pub fn cast(self, size: u32) -> Self { if self.is_signed() { if size > self.bits() && self.msb() { let mask = lookup_mask(size); @@ -536,7 +543,7 @@ impl BitVec { } } - pub fn cast_assign(&mut self, size: usize) { + pub fn cast_assign(&mut self, size: u32) { if self.is_signed() { if size > self.bits() && self.msb() { let mask = lookup_mask(size); @@ -1535,7 +1542,7 @@ impl Shr for BitVec { fn shr(self, rhs: u32) -> Self::Output { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { -Self::one(size) } else { @@ -1545,7 +1552,7 @@ impl Shr for BitVec { // perform ASR let smask = lookup_mask(self.bits()); let mask = - smask ^ ((BigInt::from(1) << (size - rhs as usize) as u32) - BigInt::from(1)); + smask ^ ((BigInt::from(1) << (size - rhs as u32) as u32) - BigInt::from(1)); Self::from_bigint_with((*self.0 >> rhs) | mask, smask) } else { let mask = lookup_mask(self.bits()); @@ -1559,7 +1566,7 @@ impl<'a> Shr for &'a BitVec { fn shr(self, rhs: u32) -> Self::Output { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { -BitVec::one(size) } else { @@ -1569,7 +1576,7 @@ impl<'a> Shr for &'a BitVec { // perform ASR let smask = lookup_mask(self.bits()); let mask = - smask ^ ((BigInt::from(1) << (size - rhs as usize) as u32) - BigInt::from(1)); + smask ^ ((BigInt::from(1) << (size - rhs as u32) as u32) - BigInt::from(1)); BitVec::from_bigint_with(BigInt::from(&*self.0 >> rhs) | mask, smask) } else { BitVec::from_bigint_with(BigInt::from(&*self.0 >> rhs), lookup_mask(self.bits())) @@ -1580,7 +1587,7 @@ impl<'a> Shr for &'a BitVec { impl ShrAssign for BitVec { fn shr_assign(&mut self, rhs: u32) { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { (*self.0).clone_from(&*lookup_mask(self.bits())); } else { @@ -1590,7 +1597,7 @@ impl ShrAssign for BitVec { // perform ASR let smask = lookup_mask(self.bits()); let mask = - smask ^ ((BigInt::from(1u32) << (size - rhs as usize) as u32) - BigInt::from(1u32)); + smask ^ ((BigInt::from(1u32) << (size - rhs as u32) as u32) - BigInt::from(1u32)); *self.0 >>= rhs; *self.0 |= mask; self.mask_assign(); @@ -1623,7 +1630,7 @@ impl Shr for BitVec { if let Some(rhs) = rhs.0.to_u32() { let smask = lookup_mask(self.bits()); let mask = smask - ^ ((BigInt::from(1) << (self.bits() - rhs as usize) as u32) - BigInt::from(1)); + ^ ((BigInt::from(1) << (self.bits() - rhs as u32) as u32) - BigInt::from(1)); Self::from_bigint_with((*self.0 >> rhs) | mask, smask) } else { -Self::one(self.bits()) @@ -1661,7 +1668,7 @@ impl<'a> Shr for &'a BitVec { if let Some(rhs) = rhs.0.to_u32() { let smask = lookup_mask(self.bits()); let mask = smask - ^ ((BigInt::from(1) << (self.bits() - rhs as usize) as u32) - BigInt::from(1)); + ^ ((BigInt::from(1) << (self.bits() - rhs as u32) as u32) - BigInt::from(1)); BitVec::from_bigint_with(BigInt::from(&*self.0 >> rhs) | mask, smask) } else { -BitVec::one(self.bits()) @@ -1730,7 +1737,7 @@ impl BitVec { if let Some(rhs) = rhs.0.to_u32() { let smask = lookup_mask(self.bits()); let mask = smask - ^ ((BigInt::from(1) << (self.bits() - rhs as usize) as u32) - BigInt::from(1)); + ^ ((BigInt::from(1) << (self.bits() - rhs as u32) as u32) - BigInt::from(1)); BitVec::from_bigint_with(BigInt::from(&*self.0 >> rhs) | mask, smask) } else { -BitVec::one(self.bits()) @@ -1754,7 +1761,7 @@ macro_rules! impl_from_for { ($t:ident) => { impl From<$t> for BitVec { fn from(t: $t) -> Self { - let bits = ::std::mem::size_of::<$t>() * 8; + let bits = ::std::mem::size_of::<$t>() as u32 * 8; BitVec::from_bigint(BigInt::from(t), bits) } } @@ -1837,7 +1844,7 @@ macro_rules! impl_from_t_for { ($t:ident) => { impl BitVec { ::paste::paste! { - pub fn [< from_ $t >](t: $t, bits: usize) -> Self { + pub fn [< from_ $t >](t: $t, bits: u32) -> Self { if bits == 0 { // || bits % 8 != 0 { panic!("bits must be > 0") // panic!("bits must be multiple of 8 and > 0") diff --git a/fugue-bv/src/core_mixed.rs b/fugue-bv/src/core_mixed.rs index b40d7c0..90501dc 100644 --- a/fugue-bv/src/core_mixed.rs +++ b/fugue-bv/src/core_mixed.rs @@ -189,7 +189,7 @@ impl FromStr for BitVec { } .map_err(|_| ParseError::InvalidConst)?; - let bits = usize::from_str(sz).map_err(|_| ParseError::InvalidSize)?; + let bits = u32::from_str(sz).map_err(|_| ParseError::InvalidSize)?; Ok(Self::from_bigint(val, bits)) } @@ -201,13 +201,13 @@ impl BitVec { let val = BigInt::from_str_radix(cst, radix as i32).map_err(|_| ParseError::InvalidConst)?; - let bits = usize::from_str(sz).map_err(|_| ParseError::InvalidSize)?; + let bits = u32::from_str(sz).map_err(|_| ParseError::InvalidSize)?; Ok(Self::from_bigint(val, bits)) } } impl BitVec { - pub fn from_bigint(v: BigInt, bits: usize) -> Self { + pub fn from_bigint(v: BigInt, bits: u32) -> Self { if bits <= 64 { let v = core_bigint::BitVec::from_bigint(v, bits).to_u64().unwrap(); Self::N(core_u64::BitVec::from_uint(v, bits)) @@ -218,7 +218,7 @@ impl BitVec { #[allow(unused)] pub(crate) fn from_bigint_with(v: BigInt, mask: &'static BigInt) -> Self { - let bits = mask.count_ones().unwrap() as usize; + let bits = mask.count_ones().unwrap() as u32; if bits <= 64 { let v = core_bigint::BitVec::from_bigint_with(v, mask) .to_u64() @@ -241,7 +241,7 @@ impl BitVec { self.as_bigint() } - pub fn zero(bits: usize) -> Self { + pub fn zero(bits: u32) -> Self { if bits <= 64 { Self::N(core_u64::BitVec::zero(bits)) } else { @@ -249,7 +249,7 @@ impl BitVec { } } - pub fn one(bits: usize) -> Self { + pub fn one(bits: u32) -> Self { if bits <= 64 { Self::N(core_u64::BitVec::one(bits)) } else { @@ -273,7 +273,7 @@ impl BitVec { fold_map!(self, |slf| slf.leading_zeros()) } - pub fn bits(&self) -> usize { + pub fn bits(&self) -> u32 { fold_map!(self, |slf| slf.bits()) } @@ -333,6 +333,11 @@ impl BitVec { fold_map!(self, |slf| slf.lsb()) } + pub fn bytes(&self) -> usize { + let bits = self.bits() as usize; + bits / 8 + if bits % 8 == 0 { 0 } else { 1 } + } + pub fn from_be_bytes(buf: &[u8]) -> Self { if buf.len() <= 8 { Self::N(core_u64::BitVec::from_be_bytes(buf)) @@ -452,7 +457,7 @@ impl BitVec { bind2!(self, rhs, |slf, rhs| slf.rem_euclid(rhs)) } - pub fn max_value_with(bits: usize, signed: bool) -> Self { + pub fn max_value_with(bits: u32, signed: bool) -> Self { if bits <= 64 { Self::N(core_u64::BitVec::max_value_with(bits, signed)) } else { @@ -464,7 +469,7 @@ impl BitVec { bind!(self, |slf| slf.max_value()) } - pub fn min_value_with(bits: usize, signed: bool) -> Self { + pub fn min_value_with(bits: u32, signed: bool) -> Self { if bits <= 64 { Self::N(core_u64::BitVec::min_value_with(bits, signed)) } else { @@ -476,28 +481,28 @@ impl BitVec { bind!(self, |slf| slf.min_value()) } - pub fn signed_cast(&self, size: usize) -> Self { + pub fn signed_cast(&self, size: u32) -> Self { self.clone().signed().cast(size) } - pub fn unsigned_cast(&self, size: usize) -> Self { + pub fn unsigned_cast(&self, size: u32) -> Self { self.clone().unsigned().cast(size) } - pub fn signed_cast_assign(&mut self, bits: usize) { + pub fn signed_cast_assign(&mut self, bits: u32) { self.cast_assign_with(true, bits) } - pub fn unsigned_cast_assign(&mut self, bits: usize) { + pub fn unsigned_cast_assign(&mut self, bits: u32) { self.cast_assign_with(false, bits) } - pub fn cast(self, size: usize) -> Self { + pub fn cast(self, size: u32) -> Self { let signed = self.is_signed(); self.cast_with(signed, size) } - fn cast_with(self, signed: bool, size: usize) -> Self { + fn cast_with(self, signed: bool, size: u32) -> Self { match self { Self::N(bv) => { if size <= 64 { @@ -534,12 +539,12 @@ impl BitVec { } } - pub fn cast_assign(&mut self, size: usize) { + pub fn cast_assign(&mut self, size: u32) { let signed = self.is_signed(); self.cast_assign_with(signed, size) } - fn cast_assign_with(&mut self, signed: bool, size: usize) { + fn cast_assign_with(&mut self, signed: bool, size: u32) { match self { Self::N(ref mut bv) => { if size <= 64 { @@ -1097,7 +1102,7 @@ macro_rules! impl_from_t_for { ($t:ident) => { impl BitVec { ::paste::paste! { - pub fn [< from_ $t >](t: $t, bits: usize) -> Self { + pub fn [< from_ $t >](t: $t, bits: u32) -> Self { if bits <= 64 { Self::N(core_u64::BitVec::[< from_ $t >](t, bits)) } else { diff --git a/fugue-bv/src/core_u64.rs b/fugue-bv/src/core_u64.rs index 984cb82..5f3d245 100644 --- a/fugue-bv/src/core_u64.rs +++ b/fugue-bv/src/core_u64.rs @@ -58,7 +58,7 @@ impl FromStr for BitVec { } .map_err(|_| ParseError::InvalidConst)?; - let bits = usize::from_str(sz).map_err(|_| ParseError::InvalidSize)?; + let bits = u32::from_str(sz).map_err(|_| ParseError::InvalidSize)?; Ok(Self::from_uint(val, bits)) } @@ -70,7 +70,7 @@ impl BitVec { (bits << 1) | (sign as u32) } - pub fn from_uint(v: u64, bits: usize) -> Self { + pub fn from_uint(v: u64, bits: u32) -> Self { Self(v, Self::pack_meta(false, bits as u32)).mask() } @@ -119,7 +119,7 @@ impl BitVec { self.0 } - pub fn zero(bits: usize) -> Self { + pub fn zero(bits: u32) -> Self { if bits == 0 { // || bits % 8 != 0 { panic!("bits must be > 0") @@ -128,7 +128,7 @@ impl BitVec { Self::from_uint(0, bits) } - pub fn one(bits: usize) -> Self { + pub fn one(bits: u32) -> Self { if bits == 0 { // || bits % 8 != 0 { panic!("bits must be > 0") @@ -157,8 +157,8 @@ impl BitVec { } } - pub fn bits(&self) -> usize { - (self.1 >> 1) as usize + pub fn bits(&self) -> u32 { + (self.1 >> 1) as u32 } pub fn signed(self) -> Self { @@ -222,6 +222,11 @@ impl BitVec { (self.0 & 1) != 0 } + pub fn bytes(&self) -> usize { + let bits = self.bits() as usize; + bits / 8 + if bits % 8 == 0 { 0 } else { 1 } + } + pub fn from_be_bytes(buf: &[u8]) -> Self { if buf.is_empty() || buf.len() > std::mem::size_of::() { panic!( @@ -230,7 +235,7 @@ impl BitVec { ) } - let bits = buf.len() * 8; + let bits = buf.len() as u32 * 8; let mut tgt = if (buf[0] & 0x80) != 0 { // signed @@ -252,7 +257,7 @@ impl BitVec { ) } - let bits = buf.len() * 8; + let bits = buf.len() as u32 * 8; let mut tgt = if (buf.last().unwrap() & 0x80) != 0 { // signed @@ -276,7 +281,7 @@ impl BitVec { } pub fn to_be_bytes(&self, buf: &mut [u8]) { - let bits = self.bits(); + let bits = self.bits() as usize; let size = bits / 8 + if bits % 8 == 0 { 0 } else { 1 }; if buf.len() != size { panic!("invalid buf size {}; expected {}", buf.len(), size); @@ -292,7 +297,7 @@ impl BitVec { } pub fn to_le_bytes(&self, buf: &mut [u8]) { - let bits = self.bits(); + let bits = self.bits() as usize; let size = bits / 8 + if bits % 8 == 0 { 0 } else { 1 }; if buf.len() != size { panic!("invalid buf size {}; expected {}", buf.len(), size); @@ -500,7 +505,7 @@ impl BitVec { } } - pub fn max_value_with(bits: usize, signed: bool) -> Self { + pub fn max_value_with(bits: u32, signed: bool) -> Self { let mask = Self::mask_value(bits as u32); if signed { Self::from_uint_with(mask.checked_shr(1).unwrap_or(0), mask).signed() @@ -520,7 +525,7 @@ impl BitVec { } } - pub fn min_value_with(bits: usize, signed: bool) -> Self { + pub fn min_value_with(bits: u32, signed: bool) -> Self { let mask = Self::mask_value(bits as u32); if signed { Self::from_uint_with(!mask.checked_shr(1).unwrap_or(0) & mask, mask) @@ -540,25 +545,25 @@ impl BitVec { } } - pub fn signed_cast(&self, size: usize) -> Self { + pub fn signed_cast(&self, size: u32) -> Self { self.clone().signed().cast(size) } - pub fn unsigned_cast(&self, size: usize) -> Self { + pub fn unsigned_cast(&self, size: u32) -> Self { self.clone().unsigned().cast(size) } - pub fn signed_cast_assign(&mut self, size: usize) { + pub fn signed_cast_assign(&mut self, size: u32) { self.signed_assign(); self.cast_assign(size) } - pub fn unsigned_cast_assign(&mut self, size: usize) { + pub fn unsigned_cast_assign(&mut self, size: u32) { self.unsigned_assign(); self.cast_assign(size) } - pub fn cast(self, size: usize) -> Self { + pub fn cast(self, size: u32) -> Self { if self.is_signed() { if size > self.bits() && self.msb() { let mask = Self::mask_value(size as u32); @@ -573,7 +578,7 @@ impl BitVec { } } - pub fn cast_assign(&mut self, size: usize) { + pub fn cast_assign(&mut self, size: u32) { if self.is_signed() { if size > self.bits() && self.msb() { let mask = Self::mask_value(size as u32); @@ -1528,7 +1533,7 @@ impl Shr for BitVec { fn shr(self, rhs: u32) -> Self::Output { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { -Self::one(size) } else { @@ -1538,7 +1543,7 @@ impl Shr for BitVec { // perform ASR let mask = self.mask_bits() ^ 1u64 - .checked_shl((size - rhs as usize) as u32) + .checked_shl((size - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); Self::from_uint_with( @@ -1556,7 +1561,7 @@ impl<'a> Shr for &'a BitVec { fn shr(self, rhs: u32) -> Self::Output { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { -BitVec::one(size) } else { @@ -1566,7 +1571,7 @@ impl<'a> Shr for &'a BitVec { // perform ASR let mask = self.mask_bits() ^ 1u64 - .checked_shl((size - rhs as usize) as u32) + .checked_shl((size - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); BitVec::from_uint_with( @@ -1582,7 +1587,7 @@ impl<'a> Shr for &'a BitVec { impl ShrAssign for BitVec { fn shr_assign(&mut self, rhs: u32) { let size = self.bits(); - if rhs as usize >= size { + if rhs as u32 >= size { if self.is_signed() { self.0 = !0; self.mask_assign(); @@ -1593,7 +1598,7 @@ impl ShrAssign for BitVec { // perform ASR let mask = self.mask_bits() ^ 1u64 - .checked_shl((size - rhs as usize) as u32) + .checked_shl((size - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); self.0 = self.0.checked_shr(rhs).unwrap_or(0) | mask; @@ -1627,7 +1632,7 @@ impl Shr for BitVec { if let Some(rhs) = rhs.0.to_u32() { let mask = self.mask_bits() ^ 1u64 - .checked_shl((self.bits() - rhs as usize) as u32) + .checked_shl((self.bits() - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); Self::from_uint_with( @@ -1669,7 +1674,7 @@ impl<'a> Shr for &'a BitVec { if let Some(rhs) = rhs.0.to_u32() { let mask = self.mask_bits() ^ 1u64 - .checked_shl((self.bits() - rhs as usize) as u32) + .checked_shl((self.bits() - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); BitVec::from_uint_with( @@ -1743,7 +1748,7 @@ impl BitVec { if let Some(rhs) = rhs.0.to_u32() { let mask = self.mask_bits() ^ 1u64 - .checked_shl((self.bits() - rhs as usize) as u32) + .checked_shl((self.bits() - rhs as u32) as u32) .unwrap_or(0) .wrapping_sub(1); BitVec::from_uint_with( @@ -1772,7 +1777,7 @@ macro_rules! impl_from_for { ($t:ident) => { impl From<$t> for BitVec { fn from(t: $t) -> Self { - let bits = ::std::mem::size_of::<$t>() * 8; + let bits = ::std::mem::size_of::<$t>() as u32 * 8; BitVec::from_uint(t.as_(), bits) } } @@ -1855,7 +1860,7 @@ macro_rules! impl_from_t_for { ($t:ident) => { impl BitVec { ::paste::paste! { - pub fn [< from_ $t >](t: $t, bits: usize) -> Self { + pub fn [< from_ $t >](t: $t, bits: u32) -> Self { if bits == 0 { // || bits % 8 != 0 { panic!("bits must be > 0") //panic!("bits must be multiple of 8 and > 0") diff --git a/fugue-core/src/eval/dummy.rs b/fugue-core/src/eval/dummy.rs index 9afb266..50d7ead 100644 --- a/fugue-core/src/eval/dummy.rs +++ b/fugue-core/src/eval/dummy.rs @@ -46,7 +46,7 @@ impl EvaluatorContext for DummyContext { fn read_vnd(&mut self, var: &VarnodeData) -> Result { let spc = var.space(); if spc.is_constant() { - Ok(BitVec::from_u64(var.offset(), var.size() * 8)) + Ok(BitVec::from_u64(var.offset(), var.bits())) } else if spc.is_register() { self.registers .read_val_with(var.offset() as usize, var.size(), self.endian) diff --git a/fugue-core/src/eval/fixed_state.rs b/fugue-core/src/eval/fixed_state.rs index b8bcc9e..09aa9e6 100644 --- a/fugue-core/src/eval/fixed_state.rs +++ b/fugue-core/src/eval/fixed_state.rs @@ -90,7 +90,7 @@ impl FixedState { ) -> Result<(), FixedStateError> { debug_assert_eq!(value.bits() % 8, 0); - let size = value.bits() / 8; + let size = value.bytes(); let view = self.view_bytes_mut(offset, size)?; if O::ENDIAN.is_big() { @@ -111,7 +111,7 @@ impl FixedState { ) -> Result<(), FixedStateError> { debug_assert_eq!(value.bits() % 8, 0); - let size = value.bits() / 8; + let size = value.bytes(); let view = self.view_bytes_mut(offset, size)?; if endian.is_big() { diff --git a/fugue-core/src/eval/mod.rs b/fugue-core/src/eval/mod.rs index 76c9023..8e4c496 100644 --- a/fugue-core/src/eval/mod.rs +++ b/fugue-core/src/eval/mod.rs @@ -279,10 +279,10 @@ where let src = self.context.read_vnd(&operation.inputs[0])?; let src_size = src.bits(); - let off = operation.inputs[1].offset() as usize * 8; + let off = operation.inputs[1].offset() as u32 * 8; let dst = operation.output.as_ref().unwrap(); - let dst_size = dst.size() * 8; + let dst_size = dst.bits(); let trun_size = src_size.saturating_sub(off); let trun = if dst_size > trun_size { @@ -326,7 +326,7 @@ where op: G, ) -> Result<(), EvaluatorError> where - F: Fn(BitVec, usize) -> BitVec, + F: Fn(BitVec, u32) -> BitVec, G: FnOnce(BitVec, BitVec) -> Result, { let lhs = self.context.read_vnd(&operation.inputs[0])?; @@ -336,7 +336,7 @@ where let siz = lhs.bits().max(rhs.bits()); let val = op(cast(lhs, siz), cast(rhs, siz))?; - self.assign(dst, val.cast(dst.size() * 8)) + self.assign(dst, val.cast(dst.bits())) } fn lift_signed_int1(&mut self, operation: &PCodeData, op: F) -> Result<(), EvaluatorError> @@ -368,7 +368,7 @@ where let val = op(cast(rhs))?; - self.assign(dst, val.cast(dst.size() * 8)) + self.assign(dst, val.cast(dst.bits())) } fn lift_bool2(&mut self, operation: &PCodeData, op: F) -> Result<(), EvaluatorError> @@ -381,7 +381,7 @@ where let val = bool2bv(op(!lhs.is_zero(), !rhs.is_zero())?); - self.assign(dst, val.cast(dst.size() * 8)) + self.assign(dst, val.cast(dst.bits())) } fn lift_bool1(&mut self, operation: &PCodeData, op: F) -> Result<(), EvaluatorError> @@ -393,7 +393,7 @@ where let val = bool2bv(op(!rhs.is_zero())?); - self.assign(dst, val.cast(dst.size() * 8)) + self.assign(dst, val.cast(dst.bits())) } fn read_bool(&mut self, var: &VarnodeData) -> Result { @@ -411,11 +411,11 @@ where } fn write_mem(&mut self, addr: Address, val: &BitVec) -> Result<(), EvaluatorError> { - let mem = VarnodeData::new(self.default_space, addr.offset(), val.bits() / 8); + let mem = VarnodeData::new(self.default_space, addr.offset(), val.bytes()); self.context.write_vnd(&mem, val) } fn assign(&mut self, var: &VarnodeData, val: BitVec) -> Result<(), EvaluatorError> { - self.context.write_vnd(var, &val.cast(var.size() * 8)) + self.context.write_vnd(var, &val.cast(var.bits())) } } diff --git a/fugue-core/src/lifter.rs b/fugue-core/src/lifter.rs index 8d3a6c9..23fc586 100644 --- a/fugue-core/src/lifter.rs +++ b/fugue-core/src/lifter.rs @@ -111,7 +111,7 @@ impl<'a> Lifter<'a> { let address_val = slf.translator.address(address.into()); let mut irbb = irb.builder(&slf.translator); - let pcode_raw = slf.translator.lift_pcode_raw_with( + let pcode_raw = slf.translator.lift_with( slf.ctx, slf.pctx, slf.irb, diff --git a/fugue-fp/src/lib.rs b/fugue-fp/src/lib.rs index bf440cc..a363ef8 100644 --- a/fugue-fp/src/lib.rs +++ b/fugue-fp/src/lib.rs @@ -721,12 +721,12 @@ impl Float { self.floor0_assign(); } - pub fn trunc_to_bitvec(&self, bits: usize) -> BitVec { + pub fn trunc_to_bitvec(&self, bits: u32) -> BitVec { let slf = self.clone(); slf.trunc_into_bitvec(bits) } - pub fn trunc_into_bitvec(self, bits: usize) -> BitVec { + pub fn trunc_into_bitvec(self, bits: u32) -> BitVec { if self.is_nan() { return BitVec::zero(bits) } @@ -1004,7 +1004,7 @@ impl FloatFormatOpsInternal for FloatFormat { } pub trait FloatFormatOps { - fn into_bitvec(&self, fp: Float, bits: usize) -> BitVec; + fn into_bitvec(&self, fp: Float, bits: u32) -> BitVec; fn from_bitvec(&self, bv: &BitVec) -> Float; } @@ -1081,7 +1081,7 @@ pub const fn float_format_from_size(bytes: usize) -> Result } impl FloatFormatOps for FloatFormat { - fn into_bitvec(&self, fp: Float, bits: usize) -> BitVec { + fn into_bitvec(&self, fp: Float, bits: u32) -> BitVec { let mut res = match fp.kind { FloatKind::QuietNaN | FloatKind::SignallingNaN => { self.encode_nan(Sign::Positive) diff --git a/fugue-ir/src/disassembly/lift.rs b/fugue-ir/src/disassembly/lift.rs index fae3aac..4a2df98 100644 --- a/fugue-ir/src/disassembly/lift.rs +++ b/fugue-ir/src/disassembly/lift.rs @@ -4,7 +4,6 @@ use std::ops::Deref; use std::sync::Arc; use ahash::AHashMap as Map; -use smallvec::SmallVec; use ustr::Ustr; use crate::address::AddressValue; @@ -15,7 +14,6 @@ use crate::disassembly::Opcode; use crate::disassembly::VarnodeData; use crate::disassembly::{Error, ParserContext, ParserWalker}; use crate::float_format::FloatFormat; -use crate::register::RegisterNames; use crate::space::AddressSpace; use crate::space_manager::SpaceManager; use crate::Translator; @@ -26,9 +24,6 @@ pub use bumpalo::format as arena_format; pub use bumpalo::vec as arena_vec; pub use bumpalo::Bump as Arena; -use crate::il::ecode::{self, ECode}; -use crate::il::pcode::{self, PCode}; - pub type FloatFormats = Map>; pub type UserOpStr = Ustr; @@ -358,9 +353,6 @@ impl IRBuilderArena { IRBuilderBase::empty( &self, translator.manager(), - translator.float_formats(), - translator.registers(), - translator.user_ops(), translator.unique_mask(), ) } @@ -402,18 +394,12 @@ pub struct IRBuilderBase<'b, 'z> { labels: ArenaVec<'z, u64>, manager: &'b SpaceManager, - float_formats: &'b FloatFormats, - registers: &'b RegisterNames, - user_ops: &'b [UserOpStr], } impl<'b, 'z> IRBuilderBase<'b, 'z> { pub fn empty( alloc: &'z IRBuilderArena, manager: &'b SpaceManager, - float_formats: &'b FloatFormats, - registers: &'b RegisterNames, - user_ops: &'b [UserOpStr], unique_mask: u64, ) -> Self { Self { @@ -425,9 +411,6 @@ impl<'b, 'z> IRBuilderBase<'b, 'z> { labels: ArenaVec::with_capacity_in(16, alloc.inner()), label_refs: ArenaVec::with_capacity_in(16, alloc.inner()), manager, - float_formats, - registers, - user_ops, } } @@ -809,7 +792,7 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> { Ok(()) } - pub fn emit_raw(self, length: usize) -> PCodeRaw<'z> { + pub fn emit(self, length: usize) -> PCodeRaw<'z> { let mut slf = self; slf.walker.base_state(); @@ -823,70 +806,4 @@ impl<'b, 'c, 'cz, 'z> IRBuilder<'b, 'c, 'cz, 'z> { length: length as u8, } } - - pub fn emit_pcode(self, length: usize) -> PCode { - let mut slf = self; - slf.walker.base_state(); - - let address = slf.walker.address(); - let delay_slots = slf.walker.delay_slot(); - - let manager = slf.manager; - let registers = slf.registers; - let user_ops = slf.user_ops; - - let mut operations = SmallVec::with_capacity(slf.issued.len()); - - for op in slf.issued.drain(..) { - operations.push(pcode::PCodeOp::from_parts( - manager, - registers, - user_ops, - op.opcode, - op.inputs.into_iter(), - op.output, - )); - } - - PCode { - operations, - address, - delay_slots, - length, - } - } - - pub fn emit_ecode(self, length: usize) -> ECode { - let mut slf = self; - slf.walker.base_state(); - - let address = slf.walker.address(); - let delay_slots = slf.walker.delay_slot(); - - let manager = slf.manager; - let float_formats = slf.float_formats; - let user_ops = slf.user_ops; - - let mut operations = SmallVec::with_capacity(slf.issued.len()); - - for (i, op) in slf.issued.drain(..).enumerate() { - operations.push(ecode::Stmt::from_parts( - manager, - &float_formats, - user_ops, - &address, - i, - op.opcode, - op.inputs.into_iter(), - op.output, - )); - } - - ECode { - operations, - address, - delay_slots, - length, - } - } } diff --git a/fugue-ir/src/disassembly/varnodedata.rs b/fugue-ir/src/disassembly/varnodedata.rs index 7c9d7b4..1b68a87 100644 --- a/fugue-ir/src/disassembly/varnodedata.rs +++ b/fugue-ir/src/disassembly/varnodedata.rs @@ -9,7 +9,7 @@ use crate::Translator; pub struct VarnodeData { pub(crate) space: AddressSpaceId, pub(crate) offset: u64, - pub(crate) size: usize, + pub(crate) size: u32, } impl Default for VarnodeData { @@ -41,7 +41,7 @@ impl<'a> fmt::Display for VarnodeDataFormatter<'a> { let space = self.translator.manager().unchecked_space_by_id(self.varnode.space); if space.is_register() { let name = self.translator.registers() - .get(self.varnode.offset, self.varnode.size) + .get(self.varnode.offset(), self.varnode.size()) .unwrap(); write!(f, "Register(name={}, size={})", name, self.varnode.size)?; return Ok(()) @@ -73,7 +73,7 @@ impl VarnodeData { Self { space: space.id(), offset, - size, + size: size as _, } } @@ -91,6 +91,10 @@ impl VarnodeData { } pub fn size(&self) -> usize { - self.size + self.size as _ + } + + pub fn bits(&self) -> u32 { + self.size * 8 } } diff --git a/fugue-ir/src/il/ecode/mod.rs b/fugue-ir/src/il/ecode/mod.rs deleted file mode 100644 index 82a3ad0..0000000 --- a/fugue-ir/src/il/ecode/mod.rs +++ /dev/null @@ -1,3853 +0,0 @@ -use std::borrow::Cow; -use std::fmt; -use std::hash::Hash; -use std::sync::Arc; - -use fugue_bv::BitVec; -use smallvec::{smallvec, SmallVec}; -use ustr::Ustr; - -use crate::address::AddressValue; -use crate::disassembly::lift::{FloatFormats, UserOpStr}; -use crate::disassembly::{IRBuilderArena, Opcode, VarnodeData}; -use crate::float_format::FloatFormat; -use crate::il::pcode::{Operand, PCode, PCodeOp}; -use crate::il::traits::*; -use crate::space::{AddressSpace, AddressSpaceId}; -use crate::space_manager::{FromSpace, IntoSpace, SpaceManager}; -use crate::Translator; - -#[derive( - Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub struct Var { - space: AddressSpaceId, - offset: u64, - bits: usize, - generation: usize, -} - -impl Var { - pub fn new>( - space: S, - offset: u64, - bits: usize, - generation: usize, - ) -> Self { - Self { - space: space.into(), - offset, - bits, - generation, - } - } - - pub fn offset(&self) -> u64 { - self.offset - } -} - -impl BitSize for Var { - fn bits(&self) -> usize { - self.bits - } -} - -impl Variable for Var { - fn generation(&self) -> usize { - self.generation - } - - fn generation_mut(&mut self) -> &mut usize { - &mut self.generation - } - - fn with_generation(&self, generation: usize) -> Self { - Self { - space: self.space.clone(), - generation, - ..*self - } - } - - fn space(&self) -> AddressSpaceId { - self.space - } -} - -impl fmt::Display for Var { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "space[{}][{:#x}].{}:{}", - self.space().index(), - self.offset(), - self.generation(), - self.bits() - ) - } -} - -impl<'var, 'trans> fmt::Display for VarFormatter<'var, 'trans> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(trans) = self.fmt.translator { - let space = trans.manager().unchecked_space_by_id(self.var.space()); - if space.is_register() { - let name = trans - .registers() - .get(self.var.offset(), self.var.bits() / 8) - .unwrap(); - write!( - f, - "{}{}{}.{}{}{}:{}{}{}", - self.fmt.variable_start, - name, - self.fmt.variable_end, - self.fmt.value_start, - self.var.generation(), - self.fmt.value_end, - self.fmt.value_start, - self.var.bits(), - self.fmt.value_end, - ) - } else { - let off = self.var.offset(); - let sig = (off as i64).signum() as i128; - write!( - f, - "{}{}{}[{}{}{}{}{:#x}{}].{}{}{}:{}{}{}", - self.fmt.variable_start, - space.name(), - self.fmt.variable_end, - self.fmt.keyword_start, - if sig == 0 { - "" - } else if sig > 0 { - "+" - } else { - "-" - }, - self.fmt.keyword_end, - self.fmt.value_start, - self.var.offset() as i64 as i128 * sig, - self.fmt.value_end, - self.fmt.value_start, - self.var.generation(), - self.fmt.value_end, - self.fmt.value_start, - self.var.bits(), - self.fmt.value_end, - ) - } - } else { - self.fmt(f) - } - } -} - -pub struct VarFormatter<'var, 'trans> { - var: &'var Var, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, -} - -impl<'var, 'trans> TranslatorDisplay<'var, 'trans> for Var { - type Target = VarFormatter<'var, 'trans>; - - fn display_full( - &'var self, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, - ) -> VarFormatter<'var, 'trans> { - VarFormatter { var: self, fmt } - } -} - -impl From for Var { - fn from(vnd: VarnodeData) -> Self { - Self { - space: vnd.space(), - offset: vnd.offset(), - bits: vnd.size() * 8, - generation: 0, - } - } -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -/// Location of the meta step -pub struct Location { - /// The address of the architecture step - address: AddressValue, - /// The index of the meta step in the decoded instruction - position: usize, -} - -impl fmt::Display for Location { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}.{}", self.address, self.position) - } -} - -impl<'loc, 'trans> TranslatorDisplay<'loc, 'trans> for Location { - type Target = &'loc Self; - - fn display_with(&'loc self, _translator: Option<&'trans Translator>) -> Self::Target { - self - } - - fn display_full(&'loc self, _fmt: Cow<'trans, TranslatorFormatter<'trans>>) -> Self::Target { - self - } -} - -impl Location { - pub fn new(address: A, position: usize) -> Location - where - A: Into, - { - Self { - address: address.into(), - position, - } - } - - pub fn address(&self) -> Cow { - Cow::Borrowed(&self.address) - } - - pub fn position(&self) -> usize { - self.position - } - - pub fn space(&self) -> AddressSpaceId { - self.address.space() - } - - pub fn is_relative(&self) -> bool { - self.space().is_constant() && self.position == 0 - } - - pub fn is_absolute(&self) -> bool { - !self.is_relative() - } - - pub fn absolute_from(&mut self, address: A, position: usize) - where - A: Into, - { - if self.is_absolute() { - return; - } - - let offset = self.address().offset() as i64; - let position = if offset.is_negative() { - position - .checked_sub(offset.abs() as usize) - .expect("negative offset from position in valid range") - } else { - position - .checked_add(offset as usize) - .expect("positive offset from position in valid range") - }; - - self.address = address.into(); - self.position = position; - } -} - -impl<'z> FromSpace<'z, VarnodeData> for Location { - fn from_space_with(t: VarnodeData, _arena: &'z IRBuilderArena, manager: &SpaceManager) -> Self { - Location::from_space(t, manager) - } - - fn from_space(vnd: VarnodeData, manager: &SpaceManager) -> Self { - Self { - address: AddressValue::new(manager.unchecked_space_by_id(vnd.space()), vnd.offset()), - position: 0, - } - } -} - -impl From for Location { - fn from(address: AddressValue) -> Self { - Self { - address, - position: 0, - } - } -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum BranchTargetT { - Location(Loc), - Computed(ExprT), -} - -impl<'target, 'trans, Loc, Val, Var> fmt::Display for BranchTargetT -where - Loc: fmt::Display, - Val: fmt::Display, - Var: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - BranchTargetT::Location(loc) => write!(f, "{}", loc), - BranchTargetT::Computed(expr) => write!(f, "{}", expr), - } - } -} - -pub struct BranchTargetTFormatter<'target, 'trans, Loc, Val, Var> { - target: &'target BranchTargetT, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, -} - -impl<'target, 'trans, Loc, Val, Var> fmt::Display - for BranchTargetTFormatter<'target, 'trans, Loc, Val, Var> -where - Loc: for<'a> TranslatorDisplay<'target, 'a>, - Val: for<'a> TranslatorDisplay<'target, 'a>, - Var: for<'a> TranslatorDisplay<'target, 'a>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.target { - BranchTargetT::Location(loc) => { - write!( - f, - "{}{}{}", - self.fmt.branch_start, - loc.display_full(Cow::Borrowed(&*self.fmt)), - self.fmt.branch_end - ) - } - BranchTargetT::Computed(expr) => { - write!(f, "{}", expr.display_full(Cow::Borrowed(&*self.fmt))) - } - } - } -} - -impl<'target, 'trans, Loc, Val, Var> TranslatorDisplay<'target, 'trans> - for BranchTargetT -where - Loc: for<'a> TranslatorDisplay<'target, 'a> + 'target, - Val: for<'a> TranslatorDisplay<'target, 'a> + 'target, - Var: for<'a> TranslatorDisplay<'target, 'a> + 'target, -{ - type Target = BranchTargetTFormatter<'target, 'trans, Loc, Val, Var>; - - fn display_full(&'target self, fmt: Cow<'trans, TranslatorFormatter<'trans>>) -> Self::Target { - BranchTargetTFormatter { target: self, fmt } - } -} - -impl From for BranchTargetT { - fn from(t: Location) -> Self { - Self::Location(t) - } -} - -impl BranchTargetT { - pub fn computed>>(expr: E) -> Self { - Self::Computed(expr.into()) - } - - pub fn is_fixed(&self) -> bool { - !self.is_computed() - } - - pub fn is_computed(&self) -> bool { - matches!(self, Self::Computed(_)) - } - - pub fn location>(location: L) -> Self { - Self::Location(location.into()) - } - - pub fn translate>( - self, - t: &T, - ) -> BranchTargetT { - match self { - BranchTargetT::Location(loc) => BranchTargetT::Location(t.translate_loc(loc)), - BranchTargetT::Computed(exp) => BranchTargetT::Computed(exp.translate(t)), - } - } -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum Cast { - Void, - Bool, // T -> Bool - - Signed(usize), // sign-extension - Unsigned(usize), // zero-extension - - Float(Arc), // T -> FloatFormat::T - - Pointer(Box, usize), - Function(Box, SmallVec<[Box; 4]>), - Named(Ustr, usize), -} - -impl fmt::Display for Cast { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Void => write!(f, "void"), - Self::Bool => write!(f, "bool"), - Self::Float(format) => write!(f, "f{}", format.bits()), - Self::Signed(bits) => write!(f, "i{}", bits), - Self::Unsigned(bits) => write!(f, "u{}", bits), - Self::Pointer(typ, _) => write!(f, "ptr<{}>", typ), - Self::Function(typ, typs) => { - write!(f, "fn(")?; - if !typs.is_empty() { - write!(f, "{}", typs[0])?; - for typ in &typs[1..] { - write!(f, "{}", typ)?; - } - } - write!(f, ") -> {}", typ) - } - Self::Named(name, _) => write!(f, "{}", name), - } - } -} - -impl BitSize for Cast { - fn bits(&self) -> usize { - match self { - Self::Void | Self::Function(_, _) => 0, // do not have a size - Self::Bool => 1, - Self::Float(format) => format.bits(), - Self::Signed(bits) - | Self::Unsigned(bits) - | Self::Pointer(_, bits) - | Self::Named(_, bits) => *bits, - } - } -} - -#[derive( - Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum UnOp { - NOT, - NEG, - - ABS, - SQRT, - CEILING, - FLOOR, - ROUND, - - POPCOUNT, - LZCOUNT, -} - -#[derive( - Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum UnRel { - NAN, -} - -#[derive( - Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum BinOp { - AND, - OR, - XOR, - ADD, - SUB, - DIV, - SDIV, - MUL, - REM, - SREM, - SHL, - SAR, - SHR, -} - -#[derive( - Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum BinRel { - EQ, - NEQ, - LT, - LE, - SLT, - SLE, - - SBORROW, - CARRY, - SCARRY, -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum ExprT { - UnRel(UnRel, Box>), // T -> bool - BinRel(BinRel, Box>, Box>), // T * T -> bool - - UnOp(UnOp, Box>), // T -> T - BinOp(BinOp, Box>, Box>), // T * T -> T - - Cast(Box>, Cast), // T -> Cast::T - Load(Box>, usize, AddressSpaceId), // SPACE[T]:SIZE -> T - - IfElse( - Box>, - Box>, - Box>, - ), // if T then T else T - - Extract(Box>, usize, usize), // T T[LSB..MSB) -> T - ExtractHigh(Box>, usize), - ExtractLow(Box>, usize), - - Concat(Box>, Box>), // T * T -> T - - Call( - Box>, - SmallVec<[Box>; 4]>, - usize, - ), - Intrinsic(UserOpStr, SmallVec<[Box>; 4]>, usize), - - Val(Val), // BitVec -> T - Var(Var), // String * usize -> T -} - -impl ExprT -where - Loc: fmt::Display, - Val: fmt::Display, - Var: fmt::Display, -{ - fn fmt_l1(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::Val(v) => write!(f, "{}", v), - ExprT::Var(v) => write!(f, "{}", v), - - ExprT::Intrinsic(name, args, _) => { - write!(f, "{}(", name)?; - if !args.is_empty() { - write!(f, "{}", args[0])?; - for arg in &args[1..] { - write!(f, ", {}", arg)?; - } - } - write!(f, ")") - } - - ExprT::ExtractHigh(expr, bits) => { - write!(f, "extract-high({}, bits={})", expr, bits) - } - ExprT::ExtractLow(expr, bits) => write!(f, "extract-low({}, bits={})", expr, bits), - - ExprT::Cast(expr, t) => { - expr.fmt_l1(f)?; - write!(f, " as {}", t) - } - - ExprT::Load(expr, bits, space) => { - write!(f, "space[{}][{}]:{}", space.index(), expr, bits) - } - - ExprT::Extract(expr, lsb, msb) => { - write!(f, "extract({}, from={}, to={})", expr, lsb, msb) - } - - ExprT::UnOp(UnOp::ABS, expr) => write!(f, "abs({})", expr), - ExprT::UnOp(UnOp::SQRT, expr) => { - write!(f, "sqrt({})", expr) - } - ExprT::UnOp(UnOp::ROUND, expr) => { - write!(f, "round({})", expr) - } - ExprT::UnOp(UnOp::CEILING, expr) => { - write!(f, "ceiling({})", expr) - } - ExprT::UnOp(UnOp::FLOOR, expr) => { - write!(f, "floor({})", expr) - } - ExprT::UnOp(UnOp::POPCOUNT, expr) => { - write!(f, "popcount({})", expr) - }, - ExprT::UnOp(UnOp::LZCOUNT, expr) => { - write!(f, "lzcount({})", expr) - } - - ExprT::UnRel(UnRel::NAN, expr) => { - write!(f, "is-nan({})", expr) - } - - ExprT::BinRel(BinRel::CARRY, e1, e2) => write!(f, "carry({}, {})", e1, e2), - ExprT::BinRel(BinRel::SCARRY, e1, e2) => write!(f, "scarry({}, {})", e1, e2), - ExprT::BinRel(BinRel::SBORROW, e1, e2) => write!(f, "sborrow({}, {})", e1, e2), - - expr => write!(f, "({})", expr), - } - } - - fn fmt_l2(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::UnOp(UnOp::NEG, expr) => { - write!(f, "-")?; - expr.fmt_l1(f) - } - ExprT::UnOp(UnOp::NOT, expr) => { - write!(f, "!")?; - expr.fmt_l1(f) - } - expr => expr.fmt_l1(f), - } - } - - fn fmt_l3(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::MUL, e1, e2) => { - e1.fmt_l3(f)?; - write!(f, " * ")?; - e2.fmt_l2(f) - } - ExprT::BinOp(BinOp::DIV, e1, e2) => { - e1.fmt_l3(f)?; - write!(f, " / ")?; - e2.fmt_l2(f) - } - ExprT::BinOp(BinOp::SDIV, e1, e2) => { - e1.fmt_l3(f)?; - write!(f, " s/ ")?; - e2.fmt_l2(f) - } - ExprT::BinOp(BinOp::REM, e1, e2) => { - e1.fmt_l3(f)?; - write!(f, " % ")?; - e2.fmt_l2(f) - } - ExprT::BinOp(BinOp::SREM, e1, e2) => { - e1.fmt_l3(f)?; - write!(f, " s% ")?; - e2.fmt_l2(f) - } - expr => expr.fmt_l2(f), - } - } - - fn fmt_l4(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::ADD, e1, e2) => { - e1.fmt_l4(f)?; - write!(f, " + ")?; - e2.fmt_l3(f) - } - ExprT::BinOp(BinOp::SUB, e1, e2) => { - e1.fmt_l4(f)?; - write!(f, " - ")?; - e2.fmt_l3(f) - } - expr => expr.fmt_l3(f), - } - } - - fn fmt_l5(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::SHL, e1, e2) => { - e1.fmt_l5(f)?; - write!(f, " << ")?; - e2.fmt_l4(f) - } - ExprT::BinOp(BinOp::SHR, e1, e2) => { - e1.fmt_l5(f)?; - write!(f, " >> ")?; - e2.fmt_l4(f) - } - ExprT::BinOp(BinOp::SAR, e1, e2) => { - e1.fmt_l5(f)?; - write!(f, " s>> ")?; - e2.fmt_l4(f) - } - expr => expr.fmt_l4(f), - } - } - - fn fmt_l6(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::BinRel(BinRel::LT, e1, e2) => { - e1.fmt_l6(f)?; - write!(f, " < ")?; - e2.fmt_l5(f) - } - ExprT::BinRel(BinRel::LE, e1, e2) => { - e1.fmt_l6(f)?; - write!(f, " <= ")?; - e2.fmt_l5(f) - } - ExprT::BinRel(BinRel::SLT, e1, e2) => { - e1.fmt_l6(f)?; - write!(f, " s< ")?; - e2.fmt_l5(f) - } - ExprT::BinRel(BinRel::SLE, e1, e2) => { - e1.fmt_l6(f)?; - write!(f, " s<= ")?; - e2.fmt_l5(f) - } - expr => expr.fmt_l5(f), - } - } - - fn fmt_l7(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExprT::BinRel(BinRel::EQ, e1, e2) => { - e1.fmt_l7(f)?; - write!(f, " == ")?; - e2.fmt_l6(f) - } - ExprT::BinRel(BinRel::NEQ, e1, e2) => { - e1.fmt_l7(f)?; - write!(f, " != ")?; - e2.fmt_l6(f) - } - expr => expr.fmt_l6(f), - } - } - - fn fmt_l8(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let ExprT::BinOp(BinOp::AND, e1, e2) = self { - e1.fmt_l8(f)?; - write!(f, " & ")?; - e2.fmt_l7(f) - } else { - self.fmt_l7(f) - } - } - - fn fmt_l9(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let ExprT::BinOp(BinOp::XOR, e1, e2) = self { - e1.fmt_l9(f)?; - write!(f, " ^ ")?; - e2.fmt_l8(f) - } else { - self.fmt_l8(f) - } - } - - fn fmt_l10(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let ExprT::BinOp(BinOp::OR, e1, e2) = self { - e1.fmt_l10(f)?; - write!(f, " | ")?; - e2.fmt_l9(f) - } else { - self.fmt_l9(f) - } - } - - fn fmt_l11(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let ExprT::Concat(e1, e2) = self { - e1.fmt_l11(f)?; - write!(f, " ++ ")?; - e2.fmt_l10(f) - } else { - self.fmt_l10(f) - } - } - - fn fmt_l12(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let ExprT::IfElse(c, et, ef) = self { - write!(f, "if ")?; - c.fmt_l12(f)?; - write!(f, " then ")?; - et.fmt_l12(f)?; - write!(f, " else ")?; - ef.fmt_l12(f) - } else { - self.fmt_l11(f) - } - } -} - -impl<'v, 't, Loc, Val, Var> ExprT -where - Loc: for<'a> TranslatorDisplay<'v, 'a>, - Val: for<'a> TranslatorDisplay<'v, 'a>, - Var: for<'a> TranslatorDisplay<'v, 'a>, -{ - fn fmt_l1_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::Val(v) => write!(f, "{}", v.display_full(Cow::Borrowed(&*d.fmt)),), - ExprT::Var(v) => write!(f, "{}", v.display_full(Cow::Borrowed(&*d.fmt))), - - ExprT::Intrinsic(name, args, _) => { - write!(f, "{}{}{}(", d.fmt.keyword_start, name, d.fmt.keyword_end)?; - if !args.is_empty() { - write!(f, "{}", args[0].display_full(Cow::Borrowed(&*d.fmt)))?; - for arg in &args[1..] { - write!(f, ", {}", arg.display_full(Cow::Borrowed(&*d.fmt)))?; - } - } - write!(f, ")") - } - - ExprT::ExtractHigh(expr, bits) => write!( - f, - "{}extract-high{}({}, {}bits{}={}{}{})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)), - d.fmt.keyword_start, - d.fmt.keyword_end, - d.fmt.value_start, - bits, - d.fmt.value_end, - ), - ExprT::ExtractLow(expr, bits) => write!( - f, - "{}extract-low{}({}, {}bits{}={}{}{})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)), - d.fmt.keyword_start, - d.fmt.keyword_end, - d.fmt.value_start, - bits, - d.fmt.value_end, - ), - - ExprT::Cast(expr, t) => { - expr.fmt_l1_with(f, d)?; - write!( - f, - " {}as{} {}{}{}", - d.fmt.keyword_start, d.fmt.keyword_end, d.fmt.type_start, t, d.fmt.type_end - ) - } - - ExprT::Load(expr, bits, space) => { - if let Some(trans) = d.fmt.translator { - let space = trans.manager().unchecked_space_by_id(*space); - write!( - f, - "{}{}{}[{}]:{}{}{}", - d.fmt.variable_start, - space.name(), - d.fmt.variable_end, - expr.display_full(Cow::Borrowed(&*d.fmt)), - d.fmt.value_start, - bits, - d.fmt.value_end, - ) - } else { - write!( - f, - "{}space{}[{}{}{}][{}]:{}{}{}", - d.fmt.variable_start, - d.fmt.variable_end, - d.fmt.value_start, - space.index(), - d.fmt.value_end, - expr.display_full(Cow::Borrowed(&*d.fmt)), - d.fmt.value_start, - bits, - d.fmt.value_end, - ) - } - } - - ExprT::Extract(expr, lsb, msb) => write!( - f, - "{}extract{}({}, {}from{}={}{}{}, {}to{}={}{}{})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)), - d.fmt.keyword_start, - d.fmt.keyword_end, - d.fmt.value_start, - lsb, - d.fmt.value_end, - d.fmt.keyword_start, - d.fmt.keyword_end, - d.fmt.value_start, - msb, - d.fmt.value_end, - ), - - ExprT::UnOp(UnOp::ABS, expr) => { - write!( - f, - "{}abs{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::SQRT, expr) => { - write!( - f, - "{}sqrt{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::ROUND, expr) => { - write!( - f, - "{}round{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::CEILING, expr) => { - write!( - f, - "{}ceiling{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::FLOOR, expr) => { - write!( - f, - "{}floor{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::POPCOUNT, expr) => { - write!( - f, - "{}popcount{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - ExprT::UnOp(UnOp::LZCOUNT, expr) => { - write!( - f, - "{}lzcount{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - - ExprT::UnRel(UnRel::NAN, expr) => { - write!( - f, - "{}is-nan{}({})", - d.fmt.keyword_start, - d.fmt.keyword_end, - expr.display_full(Cow::Borrowed(&*d.fmt)) - ) - } - - ExprT::BinRel(BinRel::CARRY, e1, e2) => write!( - f, - "{}carry{}({}, {})", - d.fmt.keyword_start, - d.fmt.keyword_end, - e1.display_full(Cow::Borrowed(&*d.fmt)), - e2.display_full(Cow::Borrowed(&*d.fmt)) - ), - ExprT::BinRel(BinRel::SCARRY, e1, e2) => write!( - f, - "{}scarry{}({}, {})", - d.fmt.keyword_start, - d.fmt.keyword_end, - e1.display_full(Cow::Borrowed(&*d.fmt)), - e2.display_full(Cow::Borrowed(&*d.fmt)) - ), - ExprT::BinRel(BinRel::SBORROW, e1, e2) => write!( - f, - "{}sborrow{}({}, {})", - d.fmt.keyword_start, - d.fmt.keyword_end, - e1.display_full(Cow::Borrowed(&*d.fmt)), - e2.display_full(Cow::Borrowed(&*d.fmt)) - ), - - expr => write!(f, "({})", expr.display_full(Cow::Borrowed(&*d.fmt))), - } - } - - fn fmt_l2_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::UnOp(UnOp::NEG, expr) => { - write!(f, "{}-{}", d.fmt.keyword_start, d.fmt.keyword_end)?; - expr.fmt_l1_with(f, d) - } - ExprT::UnOp(UnOp::NOT, expr) => { - write!(f, "{}!{}", d.fmt.keyword_start, d.fmt.keyword_end)?; - expr.fmt_l1_with(f, d) - } - expr => expr.fmt_l1_with(f, d), - } - } - - fn fmt_l3_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::MUL, e1, e2) => { - e1.fmt_l3_with(f, d)?; - write!(f, " {}*{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l2_with(f, d) - } - ExprT::BinOp(BinOp::DIV, e1, e2) => { - e1.fmt_l3_with(f, d)?; - write!(f, " {}/{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l2_with(f, d) - } - ExprT::BinOp(BinOp::SDIV, e1, e2) => { - e1.fmt_l3_with(f, d)?; - write!(f, " {}s/{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l2_with(f, d) - } - ExprT::BinOp(BinOp::REM, e1, e2) => { - e1.fmt_l3_with(f, d)?; - write!(f, " {}%{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l2_with(f, d) - } - ExprT::BinOp(BinOp::SREM, e1, e2) => { - e1.fmt_l3_with(f, d)?; - write!(f, " {}s%{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l2_with(f, d) - } - expr => expr.fmt_l2_with(f, d), - } - } - - fn fmt_l4_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::ADD, e1, e2) => { - e1.fmt_l4_with(f, d)?; - write!(f, " {}+{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l3_with(f, d) - } - ExprT::BinOp(BinOp::SUB, e1, e2) => { - e1.fmt_l4_with(f, d)?; - write!(f, " {}-{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l3_with(f, d) - } - expr => expr.fmt_l3_with(f, d), - } - } - - fn fmt_l5_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::BinOp(BinOp::SHL, e1, e2) => { - e1.fmt_l5_with(f, d)?; - write!(f, " {}<<{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l4_with(f, d) - } - ExprT::BinOp(BinOp::SHR, e1, e2) => { - e1.fmt_l5_with(f, d)?; - write!(f, " {}>>{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l4_with(f, d) - } - ExprT::BinOp(BinOp::SAR, e1, e2) => { - e1.fmt_l5_with(f, d)?; - write!(f, " {}s>>{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l4_with(f, d) - } - expr => expr.fmt_l4_with(f, d), - } - } - - fn fmt_l6_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::BinRel(BinRel::LT, e1, e2) => { - e1.fmt_l6_with(f, d)?; - write!(f, " {}<{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l5_with(f, d) - } - ExprT::BinRel(BinRel::LE, e1, e2) => { - e1.fmt_l6_with(f, d)?; - write!(f, " {}<={} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l5_with(f, d) - } - ExprT::BinRel(BinRel::SLT, e1, e2) => { - e1.fmt_l6_with(f, d)?; - write!(f, " {}s<{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l5_with(f, d) - } - ExprT::BinRel(BinRel::SLE, e1, e2) => { - e1.fmt_l6_with(f, d)?; - write!(f, " {}s<={} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l5_with(f, d) - } - expr => expr.fmt_l5_with(f, d), - } - } - - fn fmt_l7_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - match self { - ExprT::BinRel(BinRel::EQ, e1, e2) => { - e1.fmt_l7_with(f, d)?; - write!(f, " {}=={} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l6_with(f, d) - } - ExprT::BinRel(BinRel::NEQ, e1, e2) => { - e1.fmt_l7_with(f, d)?; - write!(f, " {}!={} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l6_with(f, d) - } - expr => expr.fmt_l6_with(f, d), - } - } - - fn fmt_l8_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - if let ExprT::BinOp(BinOp::AND, e1, e2) = self { - e1.fmt_l8_with(f, d)?; - write!(f, " {}&{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l7_with(f, d) - } else { - self.fmt_l7_with(f, d) - } - } - - fn fmt_l9_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - if let ExprT::BinOp(BinOp::XOR, e1, e2) = self { - e1.fmt_l9_with(f, d)?; - write!(f, " {}^{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l8_with(f, d) - } else { - self.fmt_l8_with(f, d) - } - } - - fn fmt_l10_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - if let ExprT::BinOp(BinOp::OR, e1, e2) = self { - e1.fmt_l10_with(f, d)?; - write!(f, " {}|{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l9_with(f, d) - } else { - self.fmt_l9_with(f, d) - } - } - - fn fmt_l11_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - if let ExprT::Concat(e1, e2) = self { - e1.fmt_l11_with(f, d)?; - write!(f, " {}++{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - e2.fmt_l10_with(f, d) - } else { - self.fmt_l10_with(f, d) - } - } - - fn fmt_l12_with( - &'v self, - f: &mut fmt::Formatter<'_>, - d: &ExprTFormatter<'v, 't, Loc, Val, Var>, - ) -> fmt::Result { - if let ExprT::IfElse(c, et, ef) = self { - write!(f, "{}if{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - c.fmt_l12_with(f, d)?; - write!(f, " {}then{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - et.fmt_l12_with(f, d)?; - write!(f, " {}else{} ", d.fmt.keyword_start, d.fmt.keyword_end)?; - ef.fmt_l12_with(f, d) - } else { - self.fmt_l11_with(f, d) - } - } -} - -impl fmt::Display for ExprT -where - Loc: fmt::Display, - Val: fmt::Display, - Var: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_l12(f) - } -} - -pub struct ExprTFormatter<'expr, 'trans, Loc, Val, Var> { - expr: &'expr ExprT, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, -} - -impl<'expr, 'trans, Loc, Val, Var> fmt::Display for ExprTFormatter<'expr, 'trans, Loc, Val, Var> -where - Loc: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, - Val: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, - Var: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.expr.fmt_l12_with(f, self) - } -} - -impl<'expr, 'trans, Loc, Val, Var> TranslatorDisplay<'expr, 'trans> for ExprT -where - Loc: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, - Val: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, - Var: for<'a> TranslatorDisplay<'expr, 'a> + 'expr, -{ - type Target = ExprTFormatter<'expr, 'trans, Loc, Val, Var>; - - fn display_full(&'expr self, fmt: Cow<'trans, TranslatorFormatter<'trans>>) -> Self::Target { - ExprTFormatter { expr: self, fmt } - } -} - -impl From for ExprT { - fn from(val: BitVec) -> Self { - Self::Val(val) - } -} - -impl From for ExprT { - fn from(var: Var) -> Self { - Self::Var(var) - } -} - -impl<'z, Loc> FromSpace<'z, VarnodeData> for ExprT { - fn from_space_with(t: VarnodeData, _arena: &'_ IRBuilderArena, manager: &SpaceManager) -> Self { - ExprT::from_space(t, manager) - } - - fn from_space(vnd: VarnodeData, manager: &SpaceManager) -> ExprT { - let space = manager.unchecked_space_by_id(vnd.space()); - if space.is_constant() { - ExprT::from(BitVec::from_u64(vnd.offset(), vnd.size() * 8)) - } else { - // if space.is_unique() || space.is_register() { - ExprT::from(Var::from(vnd)) - } /* else { - // address-like: the vnd size is what it points to - let asz = space.address_size() * 8; - let val = BitVec::from_u64(vnd.offset(), asz); - let src = if space.word_size() > 1 { - let s = ExprT::from(val); - let bits = s.bits(); - - let w = ExprT::from(BitVec::from_usize(space.word_size(), bits)); - - ExprT::int_mul(s, w) - } else { - ExprT::from(val) - }; - // TODO: we should preserve this information!!! - //ExprT::Cast(Box::new(src), Cast::Pointer(Box::new(Cast::Void), asz)) - ExprT::load( - src, - vnd.space().address_size() * 8, - vnd.space(), - ) - } - */ - } -} - -impl BitSize for ExprT -where - Val: BitSize, - Var: BitSize, -{ - fn bits(&self) -> usize { - match self { - Self::UnRel(_, _) | Self::BinRel(_, _, _) => 1, - Self::UnOp(_, e) | Self::BinOp(_, e, _) => e.bits(), - Self::Cast(_, cast) => cast.bits(), - Self::Load(_, bits, _) => *bits, - Self::Extract(_, lsb, msb) => *msb - *lsb, - Self::ExtractHigh(_, bits) | Self::ExtractLow(_, bits) => *bits, - Self::Concat(l, r) => l.bits() + r.bits(), - Self::IfElse(_, e, _) => e.bits(), - Self::Call(_, _, bits) => *bits, - Self::Intrinsic(_, _, bits) => *bits, - Self::Val(bv) => bv.bits(), - Self::Var(var) => var.bits(), - } - } -} - -impl ExprT -where - Val: BitSize, - Var: BitSize, -{ - pub fn is_bool(&self) -> bool { - matches!(self, Self::Cast(_, Cast::Bool)) - } - - pub fn is_float(&self) -> bool { - matches!(self, Self::Cast(_, Cast::Float(_))) - } - - pub fn is_float_format(&self, format: &FloatFormat) -> bool { - matches!(self, Self::Cast(_, Cast::Float(f)) if &**f == format) - } - - pub fn is_signed(&self) -> bool { - matches!(self, Self::Cast(_, Cast::Signed(_))) - } - - pub fn is_signed_bits(&self, bits: usize) -> bool { - matches!(self, Self::Cast(_, Cast::Signed(sz)) if *sz == bits) - } - - pub fn is_unsigned(&self) -> bool { - matches!(self, Self::Cast(_, Cast::Unsigned(_) | Cast::Pointer(_, _))) - || !matches!(self, Self::Cast(_, _)) - } - - pub fn is_unsigned_bits(&self, bits: usize) -> bool { - matches!(self, Self::Cast(_, Cast::Unsigned(sz) | Cast::Pointer(_, sz)) if *sz == bits) - || (!matches!(self, Self::Cast(_, _)) && self.bits() == bits) - } - - pub fn value(&self) -> Option<&Val> { - if let Self::Val(ref v) = self { - Some(v) - } else { - None - } - } - - pub fn cast_bool(expr: E) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_bool() { - expr - } else { - Self::Cast(expr.into(), Cast::Bool) - } - } - - pub fn cast_signed(expr: E, bits: usize) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_signed_bits(bits) { - expr - } else { - Self::Cast(expr.into(), Cast::Signed(bits)) - } - } - - pub fn cast_unsigned(expr: E, bits: usize) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_unsigned_bits(bits) { - expr - } else { - Self::Cast(expr.into(), Cast::Unsigned(bits)) - } - } - - pub fn cast_float(expr: E, format: Arc) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_float_format(&*format) { - expr - } else { - Self::Cast(expr.into(), Cast::Float(format)) - } - } - - pub fn cast(expr: E, bits: usize) -> Self - where - E: Into, - { - let expr = expr.into(); - Self::Cast(expr.into(), Cast::Unsigned(bits)) - } - - pub fn extract_high(expr: E, bits: usize) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_unsigned_bits(bits) { - expr - } else { - Self::ExtractHigh(expr.into(), bits) - } - } - - pub fn extract_low(expr: E, bits: usize) -> Self - where - E: Into, - { - let expr = expr.into(); - if expr.is_unsigned_bits(bits) { - expr - } else { - Self::ExtractLow(expr.into(), bits) - } - } - - pub fn concat(lhs: E1, rhs: E2) -> Self - where - E1: Into, - E2: Into, - { - let lhs = lhs.into(); - let rhs = rhs.into(); - Self::Concat(Box::new(lhs), Box::new(rhs)) - } - - pub(crate) fn unary_op(op: UnOp, expr: E) -> Self - where - E: Into, - { - Self::UnOp(op, Box::new(expr.into())) - } - - pub(crate) fn unary_rel(rel: UnRel, expr: E) -> Self - where - E: Into, - { - Self::cast_bool(Self::UnRel(rel, Box::new(expr.into()))) - } - - pub(crate) fn binary_op(op: BinOp, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::BinOp(op, Box::new(expr1.into()), Box::new(expr2.into())) - } - - pub(crate) fn binary_op_promote_as(op: BinOp, expr1: E1, expr2: E2, cast: F) -> Self - where - E1: Into, - E2: Into, - F: Fn(Self, usize) -> Self, - { - let e1 = expr1.into(); - let e2 = expr2.into(); - let bits = e1.bits().max(e2.bits()); - - Self::binary_op(op, cast(e1, bits), cast(e2, bits)) - } - - pub(crate) fn binary_op_promote(op: BinOp, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_as(op, expr1, expr2, |e, sz| Self::cast_unsigned(e, sz)) - } - - pub(crate) fn binary_op_promote_bool(op: BinOp, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_as(op, expr1, expr2, |e, _sz| Self::cast_bool(e)) - } - - pub(crate) fn binary_op_promote_signed(op: BinOp, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_as(op, expr1, expr2, |e, sz| Self::cast_signed(e, sz)) - } - - pub(crate) fn binary_op_promote_float( - op: BinOp, - expr1: E1, - expr2: E2, - formats: &FloatFormats, - ) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_as(op, expr1, expr2, |e, sz| { - Self::cast_float(Self::cast_signed(e, sz), formats[&sz].clone()) - }) - } - - pub(crate) fn binary_rel(rel: BinRel, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::cast_bool(Self::BinRel( - rel, - Box::new(expr1.into()), - Box::new(expr2.into()), - )) - } - - pub(crate) fn binary_rel_promote_as( - op: BinRel, - expr1: E1, - expr2: E2, - cast: F, - ) -> Self - where - E1: Into, - E2: Into, - F: Fn(Self, usize) -> Self, - { - let e1 = expr1.into(); - let e2 = expr2.into(); - let bits = e1.bits().max(e2.bits()); - - Self::binary_rel(op, cast(e1, bits), cast(e2, bits)) - } - - pub(crate) fn binary_rel_promote(op: BinRel, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_as(op, expr1, expr2, |e, sz| Self::cast_unsigned(e, sz)) - } - - pub(crate) fn binary_rel_promote_float( - op: BinRel, - expr1: E1, - expr2: E2, - formats: &FloatFormats, - ) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_as(op, expr1, expr2, |e, sz| { - Self::cast_float(Self::cast_signed(e, sz), formats[&sz].clone()) - }) - } - - pub(crate) fn binary_rel_promote_signed(op: BinRel, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_as(op, expr1, expr2, |e, sz| Self::cast_signed(e, sz)) - } - - pub(crate) fn binary_rel_promote_bool(op: BinRel, expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_as(op, expr1, expr2, |e, _sz| Self::cast_bool(e)) - } - - pub fn load(expr: E, size: usize, space: &AddressSpace) -> Self - where - E: Into, - { - Self::Load( - Box::new(Self::cast_unsigned(expr, space.address_size() * 8)), - size, - space.id(), - ) - } - - pub fn call(target: T, bits: usize) -> Self - where - T: Into>, - { - Self::Call(Box::new(target.into()), Default::default(), bits) - } - - pub fn call_with(target: T, arguments: I, bits: usize) -> Self - where - T: Into>, - I: ExactSizeIterator, - E: Into, - { - let mut args = SmallVec::with_capacity(arguments.len()); - for arg in arguments { - args.push(Box::new(arg.into())); - } - - Self::Call(Box::new(target.into()), args, bits) - } - - pub fn intrinsic(name: N, arguments: I, bits: usize) -> Self - where - N: Into, - I: ExactSizeIterator, - E: Into, - { - let mut args = SmallVec::with_capacity(arguments.len()); - for arg in arguments { - args.push(Box::new(arg.into())); - } - - Self::Intrinsic(name.into(), args, bits) - } - - pub fn extract(expr: E, loff: usize, moff: usize) -> Self - where - E: Into, - { - Self::Extract(Box::new(expr.into()), loff, moff) - } - - pub fn ite(cond: C, texpr: E1, fexpr: E2) -> Self - where - C: Into, - E1: Into, - E2: Into, - { - let e1 = texpr.into(); - let e2 = fexpr.into(); - let bits = e1.bits().max(e2.bits()); - - Self::IfElse( - Box::new(Self::cast_bool(cond)), - Box::new(Self::cast_unsigned(e1, bits)), - Box::new(Self::cast_unsigned(e2, bits)), - ) - } - - pub fn bool_not(expr: E) -> Self - where - E: Into, - { - Self::unary_op(UnOp::NOT, Self::cast_bool(expr)) - } - - pub fn bool_eq(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_bool(BinRel::EQ, expr1, expr2) - } - - pub fn bool_neq(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_bool(BinRel::NEQ, expr1, expr2) - } - - pub fn bool_and(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_bool(BinOp::AND, expr1, expr2) - } - - pub fn bool_or(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_bool(BinOp::OR, expr1, expr2) - } - - pub fn bool_xor(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_bool(BinOp::XOR, expr1, expr2) - } - - pub fn float_nan(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - - let format = formats[&bits].clone(); - - Self::unary_rel( - UnRel::NAN, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_neg(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::NEG, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_abs(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::ABS, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_sqrt(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::SQRT, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_ceiling(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::CEILING, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_round(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::ROUND, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_floor(expr: E, formats: &FloatFormats) -> Self - where - E: Into, - { - let expr = expr.into(); - let bits = expr.bits(); - let format = formats[&bits].clone(); - - Self::unary_op( - UnOp::FLOOR, - ExprT::cast_float(ExprT::cast_signed(expr, bits), format), - ) - } - - pub fn float_eq(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_float(BinRel::EQ, expr1, expr2, formats) - } - - pub fn float_neq(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_float(BinRel::NEQ, expr1, expr2, formats) - } - - pub fn float_lt(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_float(BinRel::LT, expr1, expr2, formats) - } - - pub fn float_le(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_float(BinRel::LE, expr1, expr2, formats) - } - - pub fn float_add(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_float(BinOp::ADD, expr1, expr2, formats) - } - - pub fn float_sub(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_float(BinOp::SUB, expr1, expr2, formats) - } - - pub fn float_div(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_float(BinOp::DIV, expr1, expr2, formats) - } - - pub fn float_mul(expr1: E1, expr2: E2, formats: &FloatFormats) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_float(BinOp::MUL, expr1, expr2, formats) - } - - pub fn count_ones(expr: E) -> Self - where - E: Into, - { - Self::unary_op(UnOp::POPCOUNT, expr.into()) - } - - pub fn count_leading_zeros(expr: E) -> Self - where - E: Into, - { - Self::unary_op(UnOp::LZCOUNT, expr.into()) - } - - pub fn int_neg(expr: E) -> Self - where - E: Into, - { - let expr = expr.into(); - let size = expr.bits(); - Self::unary_op(UnOp::NEG, Self::cast_signed(expr, size)) - } - - pub fn int_not(expr: E) -> Self - where - E: Into, - { - let expr = expr.into(); - let size = expr.bits(); - Self::unary_op(UnOp::NOT, Self::cast_unsigned(expr, size)) - } - - pub fn int_eq(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote(BinRel::EQ, expr1, expr2) - } - - pub fn int_neq(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote(BinRel::NEQ, expr1, expr2) - } - - pub fn int_lt(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote(BinRel::LT, expr1, expr2) - } - - pub fn int_le(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote(BinRel::LE, expr1, expr2) - } - - pub fn int_slt(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_signed(BinRel::SLT, expr1, expr2) - } - - pub fn int_sle(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_signed(BinRel::SLE, expr1, expr2) - } - - pub fn int_carry(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote(BinRel::CARRY, expr1, expr2) - } - - pub fn int_scarry(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_signed(BinRel::SCARRY, expr1, expr2) - } - - pub fn int_sborrow(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_rel_promote_signed(BinRel::SBORROW, expr1, expr2) - } - - pub fn int_add(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::ADD, expr1, expr2) - } - - pub fn int_sub(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::SUB, expr1, expr2) - } - - pub fn int_mul(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::MUL, expr1, expr2) - } - - pub fn int_div(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::DIV, expr1, expr2) - } - - pub fn int_sdiv(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_signed(BinOp::SDIV, expr1, expr2) - } - - pub fn int_rem(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::REM, expr1, expr2) - } - - pub fn int_srem(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_signed(BinOp::SREM, expr1, expr2) - } - - pub fn int_shl(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::SHL, expr1, expr2) - } - - pub fn int_shr(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::SHR, expr1, expr2) - } - - pub fn int_sar(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote_signed(BinOp::SAR, expr1, expr2) - } - - pub fn int_and(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::AND, expr1, expr2) - } - - pub fn int_or(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::OR, expr1, expr2) - } - - pub fn int_xor(expr1: E1, expr2: E2) -> Self - where - E1: Into, - E2: Into, - { - Self::binary_op_promote(BinOp::XOR, expr1, expr2) - } -} - -impl ExprT { - pub fn translate>( - self, - t: &T, - ) -> ExprT { - match self { - ExprT::Val(val) => ExprT::Val(t.translate_val(val)), - ExprT::Var(var) => ExprT::Var(t.translate_var(var)), - ExprT::UnOp(op, e) => ExprT::UnOp(op, Box::new(e.translate(t))), - ExprT::UnRel(op, e) => ExprT::UnRel(op, Box::new(e.translate(t))), - ExprT::BinOp(op, e1, e2) => { - ExprT::BinOp(op, Box::new(e1.translate(t)), Box::new(e2.translate(t))) - } - ExprT::BinRel(op, e1, e2) => { - ExprT::BinRel(op, Box::new(e1.translate(t)), Box::new(e2.translate(t))) - } - ExprT::Cast(e, c) => ExprT::Cast(Box::new(e.translate(t)), c), - ExprT::Load(e, sz, spc) => ExprT::Load(Box::new(e.translate(t)), sz, spc), - ExprT::IfElse(c, et, ef) => ExprT::IfElse( - Box::new(c.translate(t)), - Box::new(et.translate(t)), - Box::new(ef.translate(t)), - ), - ExprT::Concat(e1, e2) => { - ExprT::Concat(Box::new(e1.translate(t)), Box::new(e2.translate(t))) - } - ExprT::Extract(e, l, m) => ExprT::Extract(Box::new(e.translate(t)), l, m), - ExprT::ExtractHigh(e, b) => ExprT::ExtractHigh(Box::new(e.translate(t)), b), - ExprT::ExtractLow(e, b) => ExprT::ExtractLow(Box::new(e.translate(t)), b), - ExprT::Intrinsic(name, args, sz) => ExprT::Intrinsic( - name, - args.into_iter().map(|e| Box::new(e.translate(t))).collect(), - sz, - ), - ExprT::Call(bt, args, sz) => ExprT::Call( - Box::new(bt.translate(t)), - args.into_iter().map(|e| Box::new(e.translate(t))).collect(), - sz, - ), - } - } -} - -impl StmtT { - pub fn translate>( - self, - t: &T, - ) -> StmtT { - match self { - StmtT::Assign(v, e) => StmtT::Assign(t.translate_var(v), e.translate(t)), - StmtT::Store(e1, e2, sz, spc) => { - StmtT::Store(e1.translate(t), e2.translate(t), sz, spc) - } - StmtT::Branch(bt) => StmtT::Branch(bt.translate(t)), - StmtT::CBranch(c, bt) => StmtT::CBranch(c.translate(t), bt.translate(t)), - StmtT::Call(bt, args) => StmtT::Call( - bt.translate(t), - args.into_iter().map(|e| e.translate(t)).collect(), - ), - StmtT::Intrinsic(name, args) => { - StmtT::Intrinsic(name, args.into_iter().map(|e| e.translate(t)).collect()) - } - StmtT::Return(bt) => StmtT::Return(bt.translate(t)), - StmtT::Skip => StmtT::Skip, - } - } -} - -#[derive( - Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize, -)] -pub enum StmtT { - Assign(Var, ExprT), - - Store( - ExprT, - ExprT, - usize, - AddressSpaceId, - ), // SPACE[T]:SIZE <- T - - Branch(BranchTargetT), - CBranch(ExprT, BranchTargetT), - - Call( - BranchTargetT, - SmallVec<[ExprT; 4]>, - ), - Return(BranchTargetT), - - Skip, // NO-OP - - Intrinsic(Ustr, SmallVec<[ExprT; 4]>), // no output intrinsic -} - -impl fmt::Display for StmtT -where - Loc: fmt::Display, - Val: fmt::Display, - Var: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Assign(dest, src) => write!(f, "{} ← {}", dest, src), - Self::Store(dest, src, size, spc) => { - write!(f, "space[{}][{}]:{} ← {}", spc.index(), dest, size, src) - } - Self::Branch(target) => write!(f, "goto {}", target), - Self::CBranch(cond, target) => write!(f, "goto {} if {}", target, cond), - Self::Call(target, args) => { - if !args.is_empty() { - write!(f, "call {}(", target)?; - write!(f, "{}", args[0])?; - for arg in &args[1..] { - write!(f, ", {}", arg)?; - } - write!(f, ")") - } else { - write!(f, "call {}", target) - } - } - Self::Return(target) => write!(f, "return {}", target), - Self::Skip => write!(f, "skip"), - Self::Intrinsic(name, args) => { - write!(f, "{}(", name)?; - if !args.is_empty() { - write!(f, "{}", args[0])?; - for arg in &args[1..] { - write!(f, ", {}", arg)?; - } - } - write!(f, ")") - } - } - } -} - -impl<'stmt, 'trans, Loc, Val, Var> fmt::Display for StmtTFormatter<'stmt, 'trans, Loc, Val, Var> -where - Loc: for<'a> TranslatorDisplay<'stmt, 'a>, - Var: for<'a> TranslatorDisplay<'stmt, 'a>, - Val: for<'a> TranslatorDisplay<'stmt, 'a>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.stmt { - StmtT::Assign(dest, src) => write!( - f, - "{} {}←{} {}", - dest.display_full(Cow::Borrowed(&*self.fmt)), - self.fmt.keyword_start, - self.fmt.keyword_end, - src.display_full(Cow::Borrowed(&*self.fmt)) - ), - StmtT::Store(dest, src, size, spc) => { - if let Some(trans) = self.fmt.translator { - let space = trans.manager().unchecked_space_by_id(*spc); - write!( - f, - "{}{}{}[{}]:{}{}{} {}←{} {}", - self.fmt.variable_start, - space.name(), - self.fmt.variable_end, - dest.display_full(Cow::Borrowed(&*self.fmt)), - self.fmt.value_start, - size, - self.fmt.value_end, - self.fmt.keyword_start, - self.fmt.keyword_end, - src.display_full(Cow::Borrowed(&*self.fmt)) - ) - } else { - write!( - f, - "{}space{}[{}{}{}][{}]:{}{}{} {}←{} {}", - self.fmt.variable_start, - self.fmt.variable_end, - self.fmt.value_start, - spc.index(), - self.fmt.value_end, - dest.display_full(Cow::Borrowed(&*self.fmt)), - self.fmt.value_start, - size, - self.fmt.value_end, - self.fmt.keyword_start, - self.fmt.keyword_end, - src.display_full(Cow::Borrowed(&*self.fmt)) - ) - } - } - StmtT::Branch(target) => { - write!( - f, - "{}goto{} {}", - self.fmt.keyword_start, - self.fmt.keyword_end, - target.display_full(Cow::Borrowed(&*self.fmt)), - ) - } - StmtT::CBranch(cond, target) => write!( - f, - "{}goto{} {} {}if{} {}", - self.fmt.keyword_start, - self.fmt.keyword_end, - target.display_full(Cow::Borrowed(&*self.fmt)), - self.fmt.keyword_start, - self.fmt.keyword_end, - cond.display_full(Cow::Borrowed(&*self.fmt)) - ), - StmtT::Call(target, args) => { - if !args.is_empty() { - write!( - f, - "{}call{} {}(", - self.fmt.keyword_start, - self.fmt.keyword_end, - target.display_full(Cow::Borrowed(&*self.fmt)) - )?; - write!(f, "{}", args[0].display_full(Cow::Borrowed(&*self.fmt)))?; - for arg in &args[1..] { - write!(f, ", {}", arg.display_full(Cow::Borrowed(&*self.fmt)))?; - } - write!(f, ")") - } else { - write!( - f, - "{}call{} {}", - self.fmt.keyword_start, - self.fmt.keyword_end, - target.display_full(Cow::Borrowed(&*self.fmt)) - ) - } - } - StmtT::Return(target) => { - write!( - f, - "{}return{} {}", - self.fmt.keyword_start, - self.fmt.keyword_end, - target.display_full(Cow::Borrowed(&*self.fmt)) - ) - } - StmtT::Skip => write!(f, "{}skip{}", self.fmt.keyword_start, self.fmt.keyword_end), - StmtT::Intrinsic(name, args) => { - write!(f, "{}(", name)?; - if !args.is_empty() { - write!(f, "{}", args[0].display_full(Cow::Borrowed(&*self.fmt)))?; - for arg in &args[1..] { - write!(f, ", {}", arg.display_full(Cow::Borrowed(&*self.fmt)))?; - } - } - write!(f, ")") - } - } - } -} - -pub struct StmtTFormatter<'stmt, 'trans, Loc, Val, Var> { - stmt: &'stmt StmtT, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, -} - -impl<'stmt, 'trans, Loc, Val, Var> TranslatorDisplay<'stmt, 'trans> for StmtT -where - Loc: for<'a> TranslatorDisplay<'stmt, 'a> + 'stmt, - Var: for<'a> TranslatorDisplay<'stmt, 'a> + 'stmt, - Val: for<'a> TranslatorDisplay<'stmt, 'a> + 'stmt, -{ - type Target = StmtTFormatter<'stmt, 'trans, Loc, Val, Var>; - - fn display_full(&'stmt self, fmt: Cow<'trans, TranslatorFormatter<'trans>>) -> Self::Target { - StmtTFormatter { stmt: self, fmt } - } -} - -impl StmtT { - pub fn from_parts>( - manager: &SpaceManager, - float_formats: &FloatFormats, - user_ops: &[UserOpStr], - address: &AddressValue, - position: usize, - opcode: Opcode, - inputs: I, - output: Option, - ) -> Self { - let mut inputs = inputs.into_iter(); - let spaces = manager.spaces(); - match opcode { - Opcode::Copy => Self::assign( - output.unwrap(), - ExprT::from_space(inputs.next().unwrap(), manager), - ), - Opcode::Load => { - let space = &spaces[inputs.next().unwrap().offset() as usize]; - let destination = output.unwrap(); - let source = inputs.next().unwrap().into_space(manager); - let size = destination.size() * 8; - - let src = if space.word_size() > 1 { - let s = ExprT::from(source); - let bits = s.bits(); - - let w = ExprT::from(BitVec::from_usize(space.word_size(), bits)); - - ExprT::int_mul(s, w) - } else { - source - }; - - Self::assign(destination, ExprT::load(src, size, space)) - } - Opcode::Store => { - let space = &spaces[inputs.next().unwrap().offset() as usize]; - let destination = inputs.next().unwrap().into_space(manager); - let source = inputs.next().unwrap(); - let size = source.size() * 8; - - let dest = if space.word_size() > 1 { - let d = ExprT::from(destination); - let bits = d.bits(); - - let w = ExprT::from(BitVec::from_usize(space.word_size(), bits)); - - ExprT::int_mul(d, w) - } else { - destination - }; - - Self::store(dest, ExprT::from_space(source, manager), size, space) - } - Opcode::Branch => { - let mut target = Location::from_space(inputs.next().unwrap(), manager); - target.absolute_from(address.to_owned(), position); - - Self::branch(target) - } - Opcode::CBranch => { - let mut target = Location::from_space(inputs.next().unwrap(), manager); - target.absolute_from(address.to_owned(), position); - - let condition = ExprT::from_space(inputs.next().unwrap(), manager); - - Self::branch_conditional(condition, target) - } - Opcode::IBranch => { - let target = ExprT::from_space(inputs.next().unwrap(), manager); - let space = manager.unchecked_space_by_id(address.space()); - - Self::branch_indirect(target, space) - } - Opcode::Call => { - let mut target = Location::from_space(inputs.next().unwrap(), manager); - target.absolute_from(address.to_owned(), position); - - Self::call(target) - } - Opcode::ICall => { - let target = ExprT::from_space(inputs.next().unwrap(), manager); - let space = manager.unchecked_space_by_id(address.space()); - - Self::call_indirect(target, space) - } - Opcode::CallOther => { - // TODO: eliminate this allocation - let name = user_ops[inputs.next().unwrap().offset() as usize].clone(); - if let Some(output) = output { - let output = Var::from(output); - let bits = output.bits(); - Self::assign( - output, - ExprT::intrinsic( - &*name, - inputs.into_iter().map(|v| ExprT::from_space(v, manager)), - bits, - ), - ) - } else { - Self::intrinsic( - &*name, - inputs.into_iter().map(|v| ExprT::from_space(v, manager)), - ) - } - } - Opcode::Return => { - let target = ExprT::from_space(inputs.next().unwrap(), manager); - let space = manager.unchecked_space_by_id(address.space()); - - Self::return_(target, space) - } - Opcode::Subpiece => { - let source = ExprT::from_space(inputs.next().unwrap(), manager); - let src_size = source.bits(); - - let output = output.unwrap(); - let out_size = output.size() * 8; - - let loff = inputs.next().unwrap().offset() as usize * 8; - let trun_size = src_size.checked_sub(loff).unwrap_or(0); - - let trun = if out_size > trun_size { - // extract high + expand - let source_htrun = ExprT::extract_high(source, trun_size); - ExprT::cast_unsigned(source_htrun, out_size) - } else { - // extract - let hoff = loff + out_size; - ExprT::extract(source, loff, hoff) - }; - - Self::assign(output, trun) - } - Opcode::PopCount => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = Var::from(output.unwrap()); - - let size = output.bits(); - let popcount = ExprT::count_ones(input); - - Self::assign(output, ExprT::cast_unsigned(popcount, size)) - }, - Opcode::LZCount => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = Var::from(output.unwrap()); - - let size = output.bits(); - let lzcount = ExprT::count_leading_zeros(input); - - Self::assign(output, ExprT::cast_unsigned(lzcount, size)) - } - Opcode::BoolNot => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::bool_not(input)) - } - Opcode::BoolAnd => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::bool_and(input1, input2)) - } - Opcode::BoolOr => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::bool_or(input1, input2)) - } - Opcode::BoolXor => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::bool_xor(input1, input2)) - } - Opcode::IntNeg => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_neg(input)) - } - Opcode::IntNot => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_not(input)) - } - Opcode::IntSExt => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - let size = output.size() * 8; - - Self::assign(output, ExprT::cast_signed(input, size)) - } - Opcode::IntZExt => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - let size = output.size() * 8; - - Self::assign(output, ExprT::cast_unsigned(input, size)) - } - Opcode::IntEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_eq(input1, input2)) - } - Opcode::IntNotEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_neq(input1, input2)) - } - Opcode::IntLess => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_lt(input1, input2)) - } - Opcode::IntLessEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_le(input1, input2)) - } - Opcode::IntSLess => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_slt(input1, input2)) - } - Opcode::IntSLessEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_sle(input1, input2)) - } - Opcode::IntCarry => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_carry(input1, input2)) - } - Opcode::IntSCarry => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_scarry(input1, input2)) - } - Opcode::IntSBorrow => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_sborrow(input1, input2)) - } - Opcode::IntAdd => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_add(input1, input2)) - } - Opcode::IntSub => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_sub(input1, input2)) - } - Opcode::IntDiv => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_div(input1, input2)) - } - Opcode::IntSDiv => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_sdiv(input1, input2)) - } - Opcode::IntMul => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_mul(input1, input2)) - } - Opcode::IntRem => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_rem(input1, input2)) - } - Opcode::IntSRem => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_srem(input1, input2)) - } - Opcode::IntLShift => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_shl(input1, input2)) - } - Opcode::IntRShift => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_shr(input1, input2)) - } - Opcode::IntSRShift => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_sar(input1, input2)) - } - Opcode::IntAnd => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_and(input1, input2)) - } - Opcode::IntOr => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_or(input1, input2)) - } - Opcode::IntXor => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::int_xor(input1, input2)) - } - Opcode::FloatIsNaN => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_nan(input, float_formats)) - } - Opcode::FloatAbs => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_abs(input, float_formats)) - } - Opcode::FloatNeg => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_neg(input, float_formats)) - } - Opcode::FloatSqrt => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_sqrt(input, float_formats)) - } - Opcode::FloatFloor => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_floor(input, float_formats)) - } - Opcode::FloatCeiling => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_ceiling(input, float_formats)) - } - Opcode::FloatRound => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_round(input, float_formats)) - } - Opcode::FloatEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_eq(input1, input2, float_formats)) - } - Opcode::FloatNotEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_neq(input1, input2, float_formats)) - } - Opcode::FloatLess => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_lt(input1, input2, float_formats)) - } - Opcode::FloatLessEq => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_le(input1, input2, float_formats)) - } - Opcode::FloatAdd => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_add(input1, input2, float_formats)) - } - Opcode::FloatSub => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_sub(input1, input2, float_formats)) - } - Opcode::FloatDiv => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_div(input1, input2, float_formats)) - } - Opcode::FloatMul => { - let input1 = ExprT::from_space(inputs.next().unwrap(), manager); - let input2 = ExprT::from_space(inputs.next().unwrap(), manager); - let output = output.unwrap(); - - Self::assign(output, ExprT::float_mul(input1, input2, float_formats)) - } - Opcode::FloatOfFloat => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let input_size = input.bits(); - - let output = Var::from(output.unwrap()); - let output_size = output.bits(); - - let input_format = float_formats[&input_size].clone(); - let output_format = float_formats[&output_size].clone(); - - Self::assign( - output, - ExprT::cast_float(ExprT::cast_float(input, input_format), output_format), - ) - } - Opcode::FloatOfInt => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let input_size = input.bits(); - - let output = Var::from(output.unwrap()); - let output_size = output.bits(); - - let format = float_formats[&output_size].clone(); - Self::assign( - output, - ExprT::cast_float(ExprT::cast_signed(input, input_size), format), - ) - } - Opcode::FloatTruncate => { - let input = ExprT::from_space(inputs.next().unwrap(), manager); - let input_size = input.bits(); - - let output = Var::from(output.unwrap()); - let output_size = output.bits(); - - let format = float_formats[&input_size].clone(); - Self::assign( - output, - ExprT::cast_signed(ExprT::cast_float(input, format), output_size), - ) - } - Opcode::Label => Self::skip(), - Opcode::Build - | Opcode::CrossBuild - | Opcode::CPoolRef - | Opcode::Piece - | Opcode::Extract - | Opcode::DelaySlot - | Opcode::New - | Opcode::Insert - | Opcode::Cast - | Opcode::SegmentOp => { - panic!("unimplemented due to spec.") - } - } - } -} - -impl StmtT -where - Val: BitSize, - Var: BitSize, -{ - pub fn assign(destination: D, source: S) -> Self - where - D: Into, - S: Into>, - { - let dest = destination.into(); - let bits = dest.bits(); - Self::Assign(dest, ExprT::cast_unsigned(source, bits)) - } - - pub fn store(destination: D, source: S, size: usize, space: &AddressSpace) -> Self - where - D: Into>, - S: Into>, - { - Self::Store( - ExprT::cast_unsigned(destination.into(), space.address_size() * 8), - source.into(), - size, - space.id(), - ) - } - - pub fn branch(target: T) -> Self - where - T: Into>, - { - Self::Branch(target.into()) - } - - pub fn branch_conditional(condition: C, target: T) -> Self - where - C: Into>, - T: Into>, - { - Self::CBranch(ExprT::cast_bool(condition), target.into()) - } - - pub fn branch_indirect(target: T, space: &AddressSpace) -> Self - where - T: Into>, - { - let vptr = Cast::Pointer(Box::new(Cast::Void), space.address_size() * 8); - - Self::Branch(BranchTargetT::computed(ExprT::Cast( - Box::new(target.into()), - vptr, - ))) - /* - Self::Branch(BranchTargetT::computed(ExprT::load( - target, - space.address_size() * 8, - space, - ))) - */ - } - - pub fn call(target: T) -> Self - where - T: Into>, - { - Self::Call(target.into(), Default::default()) - } - - pub fn call_indirect(target: T, space: &AddressSpace) -> Self - where - T: Into>, - { - let fptr = Cast::Pointer( - Box::new(Cast::Function(Box::new(Cast::Void), SmallVec::new())), - space.address_size() * 8, - ); - - Self::Call( - BranchTargetT::computed(ExprT::Cast(Box::new(target.into()), fptr)), - Default::default(), - ) - } - - pub fn call_with(target: T, arguments: I) -> Self - where - T: Into>, - I: ExactSizeIterator, - E: Into>, - { - let mut args = SmallVec::with_capacity(arguments.len()); - for arg in arguments.map(|e| e.into()) { - args.push(arg); - } - - Self::Call(target.into(), args) - } - - pub fn call_indirect_with(target: T, space: &AddressSpace, arguments: I) -> Self - where - T: Into>, - I: ExactSizeIterator, - E: Into>, - { - let mut args = SmallVec::with_capacity(arguments.len()); - for arg in arguments.map(|e| e.into()) { - args.push(arg); - } - - let fptr = Cast::Pointer( - Box::new(Cast::Function(Box::new(Cast::Void), SmallVec::new())), - space.address_size() * 8, - ); - - Self::Call( - //BranchTargetT::computed(ExprT::load(target, space.address_size() * 8, space)), - BranchTargetT::computed(ExprT::Cast(Box::new(target.into()), fptr)), - args, - ) - } - - pub fn return_(target: T, space: &AddressSpace) -> Self - where - T: Into>, - { - let vptr = Cast::Pointer(Box::new(Cast::Void), space.address_size() * 8); - - Self::Return(BranchTargetT::computed(ExprT::Cast( - Box::new(target.into()), - vptr, - ))) - /* - target, - space.address_size() * 8, - space, - ))) - */ - } - - pub fn skip() -> Self { - Self::Skip - } - - pub fn intrinsic(name: N, arguments: I) -> Self - where - N: Into, - I: ExactSizeIterator, - E: Into>, - { - let mut args = SmallVec::with_capacity(arguments.len()); - for arg in arguments.map(|e| e.into()) { - args.push(arg); - } - - Self::Intrinsic(name.into(), args) - } -} - -impl<'z> FromSpace<'z, Operand> for Var { - fn from_space_with(t: Operand, _arena: &'z IRBuilderArena, manager: &SpaceManager) -> Self { - Var::from_space(t, manager) - } - - fn from_space(operand: Operand, manager: &SpaceManager) -> Self { - match operand { - Operand::Address { value, size } => Var { - offset: value.offset(), - space: manager.default_space_id(), - bits: size * 8, - generation: 0, - }, - Operand::Register { offset, size, .. } => Var { - offset, - space: manager.register_space_id(), - bits: size * 8, - generation: 0, - }, - Operand::Variable { - offset, - space, - size, - } => Var { - offset, - space, - bits: size * 8, - generation: 0, - }, - _ => panic!("cannot create Var from Operand::Constant"), - } - } -} - -impl<'z, Loc> FromSpace<'z, Operand> for ExprT { - fn from_space_with( - operand: Operand, - _arena: &'z IRBuilderArena, - manager: &SpaceManager, - ) -> Self { - ExprT::from_space(operand, manager) - } - - fn from_space(operand: Operand, manager: &SpaceManager) -> Self { - if let Operand::Constant { value, size, .. } = operand { - ExprT::Val(BitVec::from_u64(value, size * 8)) - } else { - Var::from_space(operand, manager).into() - } - } -} - -impl<'z> FromSpace<'z, Operand> for Location { - fn from_space_with(t: Operand, _arena: &'z IRBuilderArena, manager: &SpaceManager) -> Self { - Location::from_space(t, manager) - } - - fn from_space(operand: Operand, manager: &SpaceManager) -> Self { - match operand { - Operand::Address { value, .. } => Location { - address: value.into_space(manager), - position: 0, - }, - Operand::Constant { value, .. } => Location { - address: AddressValue::new(manager.constant_space_ref(), value), - position: 0, - }, - Operand::Register { offset, .. } => Location { - address: AddressValue::new(manager.register_space_ref(), offset), - position: 0, - }, - Operand::Variable { offset, space, .. } => Location { - address: AddressValue::new(manager.unchecked_space_by_id(space), offset), - position: 0, - }, - } - } -} - -impl StmtT { - pub fn from_pcode( - translator: &Translator, - pcode: PCodeOp, - address: &AddressValue, - position: usize, - ) -> Self { - let manager = translator.manager(); - let formats = translator.float_formats(); - - match pcode { - PCodeOp::Copy { - destination, - source, - } => Self::assign( - Var::from_space(destination, manager), - ExprT::from_space(source, manager), - ), - PCodeOp::Load { - destination, - source, - space, - } => { - let space = manager.unchecked_space_by_id(space); - let size = destination.size() * 8; - let src = if space.word_size() > 1 { - let s = ExprT::from_space(source, manager); - let bits = s.bits(); - - let w = ExprT::from(BitVec::from_usize(space.word_size(), bits)); - - ExprT::int_mul(s, w) - } else { - ExprT::from_space(source, manager) - }; - - Self::assign( - Var::from_space(destination, manager), - ExprT::load(src, size, space), - ) - } - PCodeOp::Store { - destination, - source, - space, - } => { - let space = manager.unchecked_space_by_id(space); - let size = source.size() * 8; - - let dest = if space.word_size() > 1 { - let d = ExprT::from_space(destination, manager); - let bits = d.bits(); - - let w = ExprT::from(BitVec::from_usize(space.word_size(), bits)); - - ExprT::int_mul(d, w) - } else { - ExprT::from_space(destination, manager) - }; - - Self::store(dest, ExprT::from_space(source, manager), size, space) - } - PCodeOp::Branch { destination } => { - let mut target = Location::from_space(destination, manager); - target.absolute_from(address.to_owned(), position); - - Self::branch(target) - } - PCodeOp::CBranch { - condition, - destination, - } => { - let mut target = Location::from_space(destination, manager); - target.absolute_from(address.to_owned(), position); - - Self::branch_conditional(ExprT::from_space(condition, manager), target) - } - PCodeOp::IBranch { destination } => { - let space = manager.unchecked_space_by_id(address.space()); - - Self::branch_indirect(ExprT::from_space(destination, manager), space) - } - PCodeOp::Call { destination } => { - let mut target = Location::from_space(destination, manager); - target.absolute_from(address.to_owned(), position); - - Self::call(target) - } - PCodeOp::ICall { destination } => { - let space = manager.unchecked_space_by_id(address.space()); - - Self::call_indirect(ExprT::from_space(destination, manager), space) - } - PCodeOp::Intrinsic { - name, - operands, - result, - } => { - if let Some(result) = result { - let output = Var::from_space(result, manager); - let bits = output.bits(); - Self::assign( - output, - ExprT::intrinsic( - &*name, - operands.into_iter().map(|v| ExprT::from_space(v, manager)), - bits, - ), - ) - } else { - Self::intrinsic( - &*name, - operands.into_iter().map(|v| ExprT::from_space(v, manager)), - ) - } - } - PCodeOp::Return { destination } => { - let space = manager.unchecked_space_by_id(address.space()); - - Self::return_(ExprT::from_space(destination, manager), space) - } - PCodeOp::Subpiece { - operand, - amount, - result, - } => { - let source = ExprT::from_space(operand, manager); - let src_size = source.bits(); - let out_size = result.size() * 8; - - let loff = amount.offset() as usize * 8; - let trun_size = src_size.checked_sub(loff).unwrap_or(0); - - let trun = if out_size > trun_size { - // extract high + expand - let source_htrun = ExprT::extract_high(source, trun_size); - ExprT::cast_unsigned(source_htrun, out_size) - } else { - // extract - let hoff = loff + out_size; - ExprT::extract(source, loff, hoff) - }; - - Self::assign(Var::from_space(result, manager), trun) - } - PCodeOp::PopCount { result, operand } => { - let output = Var::from_space(result, manager); - - let size = output.bits(); - let popcount = ExprT::unary_op(UnOp::POPCOUNT, ExprT::from_space(operand, manager)); - - Self::assign(output, ExprT::cast_unsigned(popcount, size)) - } - PCodeOp::LZCount { result, operand } => { - let output = Var::from_space(result, manager); - - let size = output.bits(); - let lzcount = ExprT::unary_op(UnOp::LZCOUNT, ExprT::from_space(operand, manager)); - - Self::assign(output, ExprT::cast_unsigned(lzcount, size)) - } - PCodeOp::BoolNot { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::bool_not(ExprT::from_space(operand, manager)), - ), - PCodeOp::BoolAnd { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::bool_and( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::BoolOr { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::bool_or( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::BoolXor { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::bool_xor( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntNeg { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::int_neg(ExprT::from_space(operand, manager)), - ), - PCodeOp::IntNot { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::int_not(ExprT::from_space(operand, manager)), - ), - PCodeOp::IntSExt { result, operand } => { - let size = result.size() * 8; - Self::assign( - Var::from_space(result, manager), - ExprT::cast_signed(ExprT::from_space(operand, manager), size), - ) - } - PCodeOp::IntZExt { result, operand } => { - let size = result.size() * 8; - Self::assign( - Var::from_space(result, manager), - ExprT::cast_unsigned(ExprT::from_space(operand, manager), size), - ) - } - PCodeOp::IntEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_eq( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntNotEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_neq( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntLess { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_lt( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntLessEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_le( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSLess { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_slt( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSLessEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_sle( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntCarry { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_carry( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSCarry { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_scarry( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSBorrow { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_sborrow( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntAdd { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_add( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSub { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_sub( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntDiv { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_div( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSDiv { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_sdiv( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntMul { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_mul( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntRem { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_rem( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSRem { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_srem( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntLeftShift { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_shl( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntRightShift { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_shr( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntSRightShift { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_sar( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntAnd { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_and( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntOr { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_or( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::IntXor { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::int_xor( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - ), - ), - PCodeOp::FloatIsNaN { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_nan(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatAbs { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_abs(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatNeg { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_neg(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatSqrt { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_sqrt(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatFloor { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_floor(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatCeiling { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_ceiling(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatRound { result, operand } => Self::assign( - Var::from_space(result, manager), - ExprT::float_round(ExprT::from_space(operand, manager), &formats), - ), - PCodeOp::FloatEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_eq( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatNotEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_neq( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatLess { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_lt( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatLessEq { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_le( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatAdd { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_add( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatSub { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_sub( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatDiv { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_div( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatMul { - result, - operands: [operand1, operand2], - } => Self::assign( - Var::from_space(result, manager), - ExprT::float_mul( - ExprT::from_space(operand1, manager), - ExprT::from_space(operand2, manager), - &formats, - ), - ), - PCodeOp::FloatOfFloat { result, operand } => { - let input = ExprT::from_space(operand, manager); - let input_size = input.bits(); - - let output = Var::from_space(result, manager); - let output_size = output.bits(); - - let input_format = formats[&input_size].clone(); - let output_format = formats[&output_size].clone(); - - Self::assign( - output, - ExprT::cast_float(ExprT::cast_float(input, input_format), output_format), - ) - } - PCodeOp::FloatOfInt { result, operand } => { - let input = ExprT::from_space(operand, manager); - let input_size = input.bits(); - - let output = Var::from_space(result, manager); - let output_size = output.bits(); - - let format = formats[&output_size].clone(); - Self::assign( - output, - ExprT::cast_float(ExprT::cast_signed(input, input_size), format), - ) - } - PCodeOp::FloatTruncate { result, operand } => { - let input = ExprT::from_space(operand, manager); - let input_size = input.bits(); - - let output = Var::from_space(result, manager); - let output_size = output.bits(); - - let format = formats[&input_size].clone(); - Self::assign( - output, - ExprT::cast_signed(ExprT::cast_float(input, format), output_size), - ) - } - PCodeOp::Skip => Self::skip(), - } - } -} - -pub type BranchTarget = BranchTargetT; -pub type Expr = ExprT; -pub type Stmt = StmtT; - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)] -pub struct ECode { - pub address: AddressValue, - pub operations: SmallVec<[Stmt; 8]>, - pub delay_slots: usize, - pub length: usize, -} - -impl ECode { - pub fn nop(address: AddressValue, length: usize) -> Self { - Self { - address, - operations: smallvec![StmtT::skip()], - delay_slots: 0, - length, - } - } - - pub fn address(&self) -> AddressValue { - self.address.clone() - } - - pub fn operations(&self) -> &[Stmt] { - self.operations.as_ref() - } - - pub fn operations_mut(&mut self) -> &mut SmallVec<[Stmt; 8]> { - &mut self.operations - } - - pub fn delay_slots(&self) -> usize { - self.delay_slots - } - - pub fn length(&self) -> usize { - self.length - } -} - -impl ECode { - pub fn from_pcode(translator: &Translator, pcode: PCode) -> Self { - let address = pcode.address; - let mut operations = SmallVec::with_capacity(pcode.operations.len()); - - for (i, op) in pcode.operations.into_iter().enumerate() { - operations.push(StmtT::from_pcode(translator, op, &address, i)); - } - - Self { - operations, - address, - delay_slots: pcode.delay_slots, - length: pcode.length, - } - } -} - -impl fmt::Display for ECode { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let len = self.operations.len(); - if len > 0 { - for (i, op) in self.operations.iter().enumerate() { - write!( - f, - "{}.{:02}: {}{}", - self.address, - i, - op, - if i == len - 1 { "" } else { "\n" } - )?; - } - Ok(()) - } else { - write!(f, "{}.00: skip", self.address) - } - } -} - -pub struct ECodeFormatter<'ecode, 'trans> { - ecode: &'ecode ECode, - fmt: Cow<'trans, TranslatorFormatter<'trans>>, -} - -impl<'v, 't> TranslatorDisplay<'v, 't> for ECode { - type Target = ECodeFormatter<'v, 't>; - - fn display_full( - &'v self, - fmt: Cow<'t, TranslatorFormatter<'t>>, - ) -> Self::Target { - ECodeFormatter { - ecode: self, - fmt, - } - } -} - -impl<'ecode, 'trans> fmt::Display for ECodeFormatter<'ecode, 'trans> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let len = self.ecode.operations.len(); - if len > 0 { - for (i, op) in self.ecode.operations.iter().enumerate() { - write!( - f, - "{}{}{}.{}{:02}{}: {}{}", - self.fmt.location_start, - self.ecode.address, - self.fmt.location_end, - self.fmt.location_start, - i, - self.fmt.location_end, - op.display_full(Cow::Borrowed(&*self.fmt)), - if i == len - 1 { "" } else { "\n" } - )?; - } - Ok(()) - } else { - write!( - f, - "{}{}{}.{}00{}: skip", - self.fmt.location_start, - self.fmt.location_end, - self.ecode.address, - self.fmt.location_start, - self.fmt.location_end - ) - } - } -} diff --git a/fugue-ir/src/il/mod.rs b/fugue-ir/src/il/mod.rs index 806de2c..985adf4 100644 --- a/fugue-ir/src/il/mod.rs +++ b/fugue-ir/src/il/mod.rs @@ -1,10 +1,2 @@ -pub mod ecode; -pub use ecode::{Location, ECode, ECodeFormatter}; - -pub mod pcode; -pub use pcode::{PCode, PCodeFormatter}; - pub mod instruction; -pub use instruction::{Instruction, InstructionFormatter}; - pub mod traits; diff --git a/fugue-ir/src/il/pcode/mod.rs b/fugue-ir/src/il/pcode/mod.rs deleted file mode 100644 index b6bed1b..0000000 --- a/fugue-ir/src/il/pcode/mod.rs +++ /dev/null @@ -1,832 +0,0 @@ -use std::fmt; - -use smallvec::SmallVec; - -use crate::disassembly::lift::UserOpStr; -use crate::disassembly::{Opcode, VarnodeData}; -use crate::address::AddressValue; -use crate::space::AddressSpaceId; -use crate::space_manager::SpaceManager; - -use crate::register::RegisterNames; - -pub mod operand; -pub use operand::Operand; - -pub mod register; -pub use register::Register; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(serde::Deserialize, serde::Serialize)] -pub enum PCodeOp { - Copy { - source: Operand, - destination: Operand, - }, - Load { - source: Operand, - destination: Operand, - space: AddressSpaceId, - }, - Store { - source: Operand, - destination: Operand, - space: AddressSpaceId, - }, - - Branch { - destination: Operand, - }, - CBranch { - destination: Operand, - condition: Operand, - }, - IBranch { - destination: Operand, - }, - - Call { - destination: Operand, - }, - ICall { - destination: Operand, - }, - Intrinsic { - name: UserOpStr, - operands: SmallVec<[Operand; 4]>, - result: Option, - }, - Return { - destination: Operand, - }, - - IntEq { - result: Operand, - operands: [Operand; 2], - }, - IntNotEq { - result: Operand, - operands: [Operand; 2], - }, - IntLess { - result: Operand, - operands: [Operand; 2], - }, - IntLessEq { - result: Operand, - operands: [Operand; 2], - }, - IntSLess { - result: Operand, - operands: [Operand; 2], - }, - IntSLessEq { - result: Operand, - operands: [Operand; 2], - }, - IntZExt { - result: Operand, - operand: Operand, - }, - IntSExt { - result: Operand, - operand: Operand, - }, - IntAdd { - result: Operand, - operands: [Operand; 2], - }, - IntSub { - result: Operand, - operands: [Operand; 2], - }, - IntCarry { - result: Operand, - operands: [Operand; 2], - }, - IntSCarry { - result: Operand, - operands: [Operand; 2], - }, - IntSBorrow { - result: Operand, - operands: [Operand; 2], - }, - IntNeg { - result: Operand, - operand: Operand, - }, - IntNot { - result: Operand, - operand: Operand, - }, - IntXor { - result: Operand, - operands: [Operand; 2], - }, - IntAnd { - result: Operand, - operands: [Operand; 2], - }, - IntOr { - result: Operand, - operands: [Operand; 2], - }, - IntLeftShift { - result: Operand, - operands: [Operand; 2], - }, - IntRightShift { - result: Operand, - operands: [Operand; 2], - }, - IntSRightShift { - result: Operand, - operands: [Operand; 2], - }, - IntMul { - result: Operand, - operands: [Operand; 2], - }, - IntDiv { - result: Operand, - operands: [Operand; 2], - }, - IntSDiv { - result: Operand, - operands: [Operand; 2], - }, - IntRem { - result: Operand, - operands: [Operand; 2], - }, - IntSRem { - result: Operand, - operands: [Operand; 2], - }, - - BoolNot { - result: Operand, - operand: Operand, - }, - BoolXor { - result: Operand, - operands: [Operand; 2], - }, - BoolAnd { - result: Operand, - operands: [Operand; 2], - }, - BoolOr { - result: Operand, - operands: [Operand; 2], - }, - - FloatEq { - result: Operand, - operands: [Operand; 2], - }, - FloatNotEq { - result: Operand, - operands: [Operand; 2], - }, - FloatLess { - result: Operand, - operands: [Operand; 2], - }, - FloatLessEq { - result: Operand, - operands: [Operand; 2], - }, - - FloatIsNaN { - result: Operand, - operand: Operand, - }, - - FloatAdd { - result: Operand, - operands: [Operand; 2], - }, - FloatDiv { - result: Operand, - operands: [Operand; 2], - }, - FloatMul { - result: Operand, - operands: [Operand; 2], - }, - FloatSub { - result: Operand, - operands: [Operand; 2], - }, - FloatNeg { - result: Operand, - operand: Operand, - }, - FloatAbs { - result: Operand, - operand: Operand, - }, - FloatSqrt { - result: Operand, - operand: Operand, - }, - - FloatOfInt { - result: Operand, - operand: Operand, - }, - FloatOfFloat { - result: Operand, - operand: Operand, - }, - FloatTruncate { - result: Operand, - operand: Operand, - }, - FloatCeiling { - result: Operand, - operand: Operand, - }, - FloatFloor { - result: Operand, - operand: Operand, - }, - FloatRound { - result: Operand, - operand: Operand, - }, - - Subpiece { - result: Operand, - operand: Operand, - amount: Operand, - }, - PopCount { - result: Operand, - operand: Operand, - }, - LZCount { - result: Operand, - operand: Operand, - }, - Skip, -} - -impl fmt::Display for PCodeOp { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Copy { destination, source } => write!(f, "{} ← {}", destination, source)?, - Self::Load { destination, source, .. } => write!(f, "{} ← *{}", destination, source)?, - Self::Store { destination, source, .. } => write!(f, "*{} ← {}", destination, source)?, - - Self::Branch { destination } => write!(f, "goto {}", destination)?, - Self::CBranch { destination, condition } => write!(f, "goto {} if {} == 0x1", destination, condition)?, - Self::IBranch { destination } => write!(f, "goto [{}]", destination)?, - - Self::Call { destination } => write!(f, "call {}", destination)?, - Self::ICall { destination } => write!(f, "call [{}]", destination)?, - Self::Return { destination } => write!(f, "return [{}]", destination)?, - - Self::Intrinsic { name, operands, result } => { - if let Some(result) = result { - write!(f, "{} ← ", result)?; - } - write!(f, "{}(", name.to_lowercase())?; - if operands.len() > 0 { - write!(f, "{}", operands[0])?; - for oper in &operands[1..] { - write!(f, ", {}", oper)?; - } - } - write!(f, ")")?; - }, - - Self::IntEq { result, operands } => write!(f, "{} ← {} == {}", result, operands[0], operands[1])?, - Self::IntNotEq { result, operands } => write!(f, "{} ← {} != {}", result, operands[0], operands[1])?, - Self::IntSLess { result, operands } => write!(f, "{} ← {} s< {}", result, operands[0], operands[1])?, - Self::IntSLessEq { result, operands } => write!(f, "{} ← {} s<= {}", result, operands[0], operands[1])?, - Self::IntLess { result, operands } => write!(f, "{} ← {} < {}", result, operands[0], operands[1])?, - Self::IntLessEq { result, operands } => write!(f, "{} ← {} <= {}", result, operands[0], operands[1])?, - - Self::IntZExt { result, operand } => write!(f, "{} ← zext({}, {})", result, operand, result.size() * 8)?, - Self::IntSExt { result, operand } => write!(f, "{} ← sext({}, {})", result, operand, result.size() * 8)?, - - Self::IntAdd { result, operands } => write!(f, "{} ← {} + {}", result, operands[0], operands[1])?, - Self::IntSub { result, operands } => write!(f, "{} ← {} - {}", result, operands[0], operands[1])?, - Self::IntCarry { result, operands } => write!(f, "{} ← carry({}, {})", result, operands[0], operands[1])?, - Self::IntSCarry { result, operands } => write!(f, "{} ← scarry({}, {})", result, operands[0], operands[1])?, - Self::IntSBorrow { result, operands } => write!(f, "{} ← sborrow({}, {})", result, operands[0], operands[1])?, - - Self::IntNeg { result, operand } => write!(f, "{} ← -{}", result, operand)?, - Self::IntNot { result, operand } => write!(f, "{} ← ~{}", result, operand)?, - - Self::IntXor { result, operands } => write!(f, "{} ← {} ^ {}", result, operands[0], operands[1])?, - Self::IntAnd { result, operands } => write!(f, "{} ← {} & {}", result, operands[0], operands[1])?, - Self::IntOr { result, operands } => write!(f, "{} ← {} | {}", result, operands[0], operands[1])?, - Self::IntLeftShift { result, operands } => write!(f, "{} ← {} << {}", result, operands[0], operands[1])?, - Self::IntRightShift { result, operands } => write!(f, "{} ← {} >> {}", result, operands[0], operands[1])?, - Self::IntSRightShift { result, operands } => write!(f, "{} ← {} s>> {}", result, operands[0], operands[1])?, - - Self::IntMul { result, operands } => write!(f, "{} ← {} * {}", result, operands[0], operands[1])?, - Self::IntDiv { result, operands } => write!(f, "{} ← {} / {}", result, operands[0], operands[1])?, - Self::IntSDiv { result, operands } => write!(f, "{} ← {} s/ {}", result, operands[0], operands[1])?, - Self::IntRem { result, operands } => write!(f, "{} ← {} % {}", result, operands[0], operands[1])?, - Self::IntSRem { result, operands } => write!(f, "{} ← {} s% {}", result, operands[0], operands[1])?, - - Self::BoolNot { result, operand } => write!(f, "{} ← !{}", result, operand)?, - Self::BoolXor { result, operands } => write!(f, "{} ← {} ^ {}", result, operands[0], operands[1])?, - Self::BoolAnd { result, operands } => write!(f, "{} ← {} & {}", result, operands[0], operands[1])?, - Self::BoolOr { result, operands } => write!(f, "{} ← {} | {}", result, operands[0], operands[1])?, - - Self::FloatEq { result, operands } => write!(f, "{} ← {} f== {}", result, operands[0], operands[1])?, - Self::FloatNotEq { result, operands } => write!(f, "{} ← {} f!= {}", result, operands[0], operands[1])?, - Self::FloatLess { result, operands } => write!(f, "{} ← {} f< {}", result, operands[0], operands[1])?, - Self::FloatLessEq { result, operands } => write!(f, "{} ← {} f<= {}", result, operands[0], operands[1])?, - - Self::FloatIsNaN { result, operand } => write!(f, "{} ← nan({})", result, operand)?, - - Self::FloatAdd { result, operands } => write!(f, "{} ← {} f+ {}", result, operands[0], operands[1])?, - Self::FloatDiv { result, operands } => write!(f, "{} ← {} f/ {}", result, operands[0], operands[1])?, - Self::FloatMul { result, operands } => write!(f, "{} ← {} f* {}", result, operands[0], operands[1])?, - Self::FloatSub { result, operands } => write!(f, "{} ← {} f- {}", result, operands[0], operands[1])?, - - Self::FloatNeg { result, operand } => write!(f, "{} ← f-{}", result, operand)?, - Self::FloatAbs { result, operand } => write!(f, "{} ← abs({})", result, operand)?, - Self::FloatSqrt { result, operand } => write!(f, "{} ← sqrt({})", result, operand)?, - - Self::FloatOfInt { result, operand } => write!(f, "{} ← float-of-int{}({})", result.size() * 8, result, operand)?, - Self::FloatOfFloat { result, operand } => write!(f, "{} ← float-of-float{}({})", result.size() * 8, result, operand)?, - Self::FloatTruncate { result, operand } => write!(f, "{} ← truncate({}, {})", result, operand, result.size() * 8)?, - Self::FloatCeiling { result, operand } => write!(f, "{} ← ceiling({})", result, operand)?, - Self::FloatFloor { result, operand } => write!(f, "{} ← floor({})", result, operand)?, - Self::FloatRound { result, operand } => write!(f, "{} ← round({})", result, operand)?, - - Self::Subpiece { result, operand, amount } => write!(f, "{} ← subpiece({}, {})", result, operand, amount)?, - Self::PopCount { result, operand } => write!(f, "{} ← popcount({})", result, operand)?, - Self::LZCount { result, operand } => write!(f, "{} ← lzcount({})", result, operand)?, - Self::Skip => write!(f, "skip")?, - } - Ok(()) - } -} - -impl PCodeOp { - pub(crate) fn from_parts>( - manager: &SpaceManager, - registers: &RegisterNames, - user_ops: &[UserOpStr], - opcode: Opcode, - inputs: I, - output: Option, - ) -> Self { - let mut inputs = inputs.into_iter(); - - if cfg!(feature = "extra-logging") { - log::trace!("lifting opcode {opcode:?}"); - } - - unsafe { match opcode { - Opcode::Copy => PCodeOp::Copy { - destination: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - source: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::Load => { - let space = manager.spaces()[inputs.next().unwrap_unchecked().offset() as usize].id(); - let destination = output.unwrap_unchecked(); - let source = inputs.next().unwrap_unchecked(); - - PCodeOp::Load { - destination: Operand::from_varnodedata(manager, registers, destination), - source: Operand::from_varnodedata(manager, registers, source), - space, - } - }, - Opcode::Store => { - let space = manager.spaces()[inputs.next().unwrap_unchecked().offset() as usize].id(); - let destination = inputs.next().unwrap_unchecked(); - let source = inputs.next().unwrap_unchecked(); - - PCodeOp::Store { - destination: Operand::from_varnodedata(manager, registers, destination), - source: Operand::from_varnodedata(manager, registers, source), - space, - } - }, - Opcode::Branch => PCodeOp::Branch { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::CBranch => PCodeOp::CBranch { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - condition: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::IBranch => PCodeOp::IBranch { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::Call => PCodeOp::Call { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::ICall => PCodeOp::ICall { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::CallOther => { - let name = user_ops[inputs.next().unwrap_unchecked().offset() as usize].clone(); - let result = output.map(|output| Operand::from_varnodedata(manager, registers, output)); - - let mut operands = SmallVec::with_capacity(inputs.len()); - operands.extend(inputs.into_iter().map(|vnd| Operand::from_varnodedata(manager, registers, vnd))); - - PCodeOp::Intrinsic { - name, - operands, - result, - } - }, - Opcode::Return => PCodeOp::Return { - destination: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - }, - Opcode::Subpiece => PCodeOp::Subpiece { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - amount: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::PopCount => PCodeOp::PopCount { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::LZCount => PCodeOp::LZCount { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::BoolNot => PCodeOp::BoolNot { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::BoolAnd => PCodeOp::BoolAnd { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::BoolOr => PCodeOp::BoolOr { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::BoolXor => PCodeOp::BoolXor { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntNeg => PCodeOp::IntNeg { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntNot => PCodeOp::IntNot { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSExt => PCodeOp::IntSExt { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntZExt => PCodeOp::IntZExt { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntEq => PCodeOp::IntEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntNotEq => PCodeOp::IntNotEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntLess => PCodeOp::IntLess { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntLessEq => PCodeOp::IntLessEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSLess => PCodeOp::IntSLess { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSLessEq => PCodeOp::IntSLessEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntCarry => PCodeOp::IntCarry { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSCarry => PCodeOp::IntSCarry { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSBorrow => PCodeOp::IntSBorrow { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntAdd => PCodeOp::IntAdd { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSub => PCodeOp::IntSub { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntDiv => PCodeOp::IntDiv { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSDiv => PCodeOp::IntSDiv { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntMul => PCodeOp::IntMul { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntRem => PCodeOp::IntRem { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSRem => PCodeOp::IntSRem { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntLShift => PCodeOp::IntLeftShift { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntRShift => PCodeOp::IntRightShift { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntSRShift => PCodeOp::IntSRightShift { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntAnd => PCodeOp::IntAnd { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntOr => PCodeOp::IntOr { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::IntXor => PCodeOp::IntXor { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatIsNaN => PCodeOp::FloatIsNaN { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatAbs => PCodeOp::FloatAbs { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatNeg => PCodeOp::FloatNeg { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatSqrt => PCodeOp::FloatSqrt { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatFloor => PCodeOp::FloatFloor { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatCeiling => PCodeOp::FloatCeiling { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatRound => PCodeOp::FloatRound { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatEq => PCodeOp::FloatEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatNotEq => PCodeOp::FloatNotEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatLess => PCodeOp::FloatLess { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatLessEq => PCodeOp::FloatLessEq { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatAdd => PCodeOp::FloatAdd { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatSub => PCodeOp::FloatSub { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatDiv => PCodeOp::FloatDiv { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatMul => PCodeOp::FloatMul { - operands: [ - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - ], - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatOfFloat => PCodeOp::FloatOfFloat { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatOfInt => PCodeOp::FloatOfInt { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::FloatTruncate => PCodeOp::FloatTruncate { - operand: Operand::from_varnodedata(manager, registers, inputs.next().unwrap_unchecked()), - result: Operand::from_varnodedata(manager, registers, output.unwrap_unchecked()), - }, - Opcode::Label => PCodeOp::Skip, - Opcode::Build - | Opcode::CrossBuild - | Opcode::CPoolRef - | Opcode::Piece - | Opcode::Extract - | Opcode::DelaySlot - | Opcode::New - | Opcode::Insert - | Opcode::Cast - | Opcode::SegmentOp => { - panic!("{:?} unimplemented due to spec", opcode) - } - } } - } - - pub fn skip() -> Self { - PCodeOp::Skip - } -} - -#[derive(Debug, Clone)] -#[derive(serde::Deserialize, serde::Serialize)] -pub struct PCode { - pub address: AddressValue, - pub operations: SmallVec<[PCodeOp; 8]>, - pub delay_slots: usize, - pub length: usize, -} - -impl PCode { - pub fn nop(address: AddressValue, length: usize) -> Self { - Self { - address, - operations: SmallVec::new(), - delay_slots: 0, - length, - } - } - - pub fn address(&self) -> AddressValue { - self.address.clone() - } - - pub fn operations(&self) -> &[PCodeOp] { - self.operations.as_ref() - } - - pub fn delay_slots(&self) -> usize { - self.delay_slots - } - - pub fn length(&self) -> usize { - self.length - } - - pub fn display<'pcode>(&'pcode self) -> PCodeFormatter<'pcode> { - PCodeFormatter { pcode: self } - } -} - -pub struct PCodeFormatter<'pcode> { - pcode: &'pcode PCode, -} - -impl<'pcode> fmt::Display for PCodeFormatter<'pcode> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let len = self.pcode.operations.len(); - if len > 0 { - for (i, op) in self.pcode.operations.iter().enumerate() { - write!(f, "{}.{:02}: {}{}", self.pcode.address, i, - op, - if i == len - 1 { "" } else { "\n" })?; - } - Ok(()) - } else { - write!(f, "{}.00: skip", self.pcode.address) - } - } -} diff --git a/fugue-ir/src/il/pcode/operand.rs b/fugue-ir/src/il/pcode/operand.rs deleted file mode 100644 index 53e4937..0000000 --- a/fugue-ir/src/il/pcode/operand.rs +++ /dev/null @@ -1,274 +0,0 @@ -use std::fmt; - -use crate::address::Address; -use crate::disassembly::VarnodeData; -use crate::register::RegisterNames; -use crate::space::AddressSpaceId; -use crate::space_manager::SpaceManager; -use crate::translator::Translator; - -use fugue_bv::BitVec; -use ustr::Ustr; - -use super::Register; - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[derive(serde::Deserialize, serde::Serialize)] -pub enum Operand { - // RAM - Address { - value: Address, - size: usize, - }, - Constant { - value: u64, - size: usize, - }, - Register { - name: Ustr, - offset: u64, - size: usize, - }, - Variable { - offset: u64, - size: usize, - space: AddressSpaceId, - }, -} - -impl<'z> Operand { - pub fn from_varnode(translator: &Translator, varnode: VarnodeData) -> Operand { - Self::from_varnodedata(translator.manager(), translator.registers(), varnode) - } - - #[inline(always)] - pub(crate) fn from_varnodedata( - manager: &SpaceManager, - registers: &RegisterNames, - vnd: VarnodeData, - ) -> Operand { - let offset = vnd.offset; - let size = vnd.size; - let space_id = vnd.space; - - if cfg!(feature = "extra-logging") { - log::trace!("building operand from {vnd:?}"); - } - - if space_id.is_default() { - // address - Operand::Address { - value: Address::new(manager.default_space_ref(), offset), - size, - } - } else if space_id.is_constant() { - // constant - Operand::Constant { - value: offset, - size, - } - } else if space_id.is_register() { - // register - let name = registers.unchecked_get(offset, size).clone(); - - Operand::Register { - name, - offset, - size, - } - } else { - // variable - Operand::Variable { - offset, - size, - space: space_id, - } - } - } - - pub fn address(&self) -> Option
{ - if let Self::Address { value, .. } = self { - Some(*value) - } else { - None - } - } - - pub fn as_bitvec(&self) -> Option { - if let Self::Constant { value, size, .. } = self { - Some(BitVec::from_u64(*value, size * 8)) - } else { - None - } - } - - pub fn register(&self) -> Option { - if let Self::Register { - name, - offset, - size, - } = self - { - Some(Register { - name: name.clone(), - offset: *offset, - size: *size, - }) - } else { - None - } - } - - pub fn offset(&self) -> u64 { - match self { - Operand::Address { value, .. } => value.offset(), - Operand::Constant { value, .. } => *value, - Operand::Register { offset, .. } | Operand::Variable { offset, .. } => *offset, - } - } - - pub fn size(&self) -> usize { - match self { - Operand::Address { size, .. } - | Operand::Constant { size, .. } - | Operand::Register { size, .. } - | Operand::Variable { size, .. } => *size, - } - } - - pub fn display(&self) -> OperandFormatter { - OperandFormatter::new(self) - } -} - -impl<'z> fmt::Display for Operand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.display()) - } -} - -impl<'z> AsRef for Operand { - fn as_ref(&self) -> &Operand { - self - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum OperandCase { - Default, - Lower, - Upper, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum OperandSize { - Default, - AsBits, - AsBytes, -} - -impl Default for OperandSize { - fn default() -> Self { - Self::Default - } -} - -pub struct OperandFormatter<'operand> { - operand: &'operand Operand, - signed: bool, - sizes: OperandSize, - case: OperandCase, -} - -impl Default for OperandCase { - fn default() -> Self { - Self::Default - } -} - -impl<'operand> OperandFormatter<'operand> { - pub fn new(operand: &'operand Operand) -> Self { - Self { - operand, - signed: false, - sizes: OperandSize::default(), - case: OperandCase::default(), - } - } - - pub fn signed(self, signed: bool) -> Self { - Self { signed, ..self } - } - - pub fn case(self, case: OperandCase) -> Self { - Self { case, ..self } - } - - pub fn sizes(self, sizes: OperandSize) -> Self { - Self { sizes, ..self } - } -} - -impl<'operand> fmt::Debug for OperandFormatter<'operand> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.operand) - } -} - -impl<'operand> fmt::Display for OperandFormatter<'operand> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.operand { - Operand::Address { value, .. } => write!(f, "{}", value)?, - Operand::Constant { value, size, .. } => { - if !self.signed { - match size { - 1 => write!(f, "{:#x}", *value as u8)?, - 2 => write!(f, "{:#x}", *value as u16)?, - 4 => write!(f, "{:#x}", *value as u32)?, - _ => write!(f, "{:#x}", value)?, - } - } else { - match size { - 1 => { - let i = *value as u8 as i8; - write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())? - } - 2 => { - let i = *value as u16 as i16; - write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())? - } - 4 => { - let i = *value as u32 as i32; - write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())? - } - _ => { - let i = *value as u64 as i64; - write!(f, "{}{:#x}", if i < 0 { "-" } else { "" }, i.abs())? - } - } - } - } - Operand::Register { name, .. } => match self.case { - OperandCase::Default => write!(f, "{}", name)?, - OperandCase::Lower => write!(f, "{}", name.to_lowercase())?, - OperandCase::Upper => write!(f, "{}", name.to_uppercase())?, - }, - Operand::Variable { offset, .. } => write!( - f, - "{}{:04x}", - if matches!(self.case, OperandCase::Upper) { - "VAR" - } else { - "var" - }, - offset - )?, - } - match self.sizes { - OperandSize::Default => (), - OperandSize::AsBits => write!(f, ":{}", self.operand.size() * 8)?, - OperandSize::AsBytes => write!(f, ":{}", self.operand.size())?, - } - Ok(()) - } -} diff --git a/fugue-ir/src/il/pcode/register.rs b/fugue-ir/src/il/pcode/register.rs deleted file mode 100644 index 74c8cbc..0000000 --- a/fugue-ir/src/il/pcode/register.rs +++ /dev/null @@ -1,47 +0,0 @@ -use ustr::Ustr; - -use super::operand::Operand; - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[derive(serde::Deserialize, serde::Serialize)] -pub struct Register { - pub(crate) name: Ustr, - pub(crate) offset: u64, - pub(crate) size: usize, -} - -impl From for Operand { - fn from(src: Register) -> Operand { - Operand::Register { - offset: src.offset(), - size: src.size(), - name: src.name, - } - } -} - -impl Register { - pub fn new(name: N, offset: u64, size: usize) -> Self - where N: Into { - Self { - name: name.into(), - offset, - size, - } - } - - #[inline] - pub fn name(&self) -> &str { - self.name.as_ref() - } - - #[inline] - pub fn offset(&self) -> u64 { - self.offset - } - - #[inline] - pub fn size(&self) -> usize { - self.size - } -} diff --git a/fugue-ir/src/il/traits/mod.rs b/fugue-ir/src/il/traits/mod.rs index f858b3f..d48c7fb 100644 --- a/fugue-ir/src/il/traits/mod.rs +++ b/fugue-ir/src/il/traits/mod.rs @@ -6,14 +6,14 @@ use std::borrow::Cow; use std::fmt; pub trait BitSize { - fn bits(&self) -> usize; + fn bits(&self) -> u32; } pub trait Variable { fn space(&self) -> AddressSpaceId; - fn generation(&self) -> usize; - fn generation_mut(&mut self) -> &mut usize; - fn with_generation(&self, generation: usize) -> Self; + fn generation(&self) -> u32; + fn generation_mut(&mut self) -> &mut u32; + fn with_generation(&self, generation: u32) -> Self; } pub trait TranslateIR { @@ -92,7 +92,7 @@ pub trait TranslatorDisplay<'v, 't> { } impl BitSize for BitVec { - fn bits(&self) -> usize { + fn bits(&self) -> u32 { self.bits() } } diff --git a/fugue-ir/src/lib.rs b/fugue-ir/src/lib.rs index 2858158..1e2f93b 100644 --- a/fugue-ir/src/lib.rs +++ b/fugue-ir/src/lib.rs @@ -20,7 +20,6 @@ pub mod translator; pub use address::{Address, AddressValue, IntoAddress}; pub use disassembly::{IRBuilder, VarnodeData}; -pub use il::{PCode, PCodeFormatter}; pub use language::LanguageDB; pub use space::{AddressSpace, AddressSpaceId}; pub use space_manager::SpaceManager; diff --git a/fugue-ir/src/translator.rs b/fugue-ir/src/translator.rs index 9b7bed3..edd2cc1 100644 --- a/fugue-ir/src/translator.rs +++ b/fugue-ir/src/translator.rs @@ -1,5 +1,4 @@ use std::borrow::Borrow; -use std::convert::TryFrom; use std::fs::File; use std::io::Read; use std::path::Path; @@ -13,10 +12,10 @@ use itertools::Itertools; use ustr::Ustr; use crate::address::AddressValue; - +use crate::compiler; +use crate::convention::Convention; use crate::deserialise::parse::XmlExt; use crate::deserialise::Error as DeserialiseError; - use crate::disassembly::lift::{FloatFormats, UserOpStr}; use crate::disassembly::symbol::{FixedHandle, Symbol, SymbolScope, SymbolTable}; use crate::disassembly::walker::InstructionFormatter; @@ -27,18 +26,9 @@ use crate::disassembly::VarnodeData; use crate::disassembly::{ IRBuilder, IRBuilderArena, IRBuilderBase, PCodeRaw, ParserContext, ParserState, ParserWalker, }; - -use crate::il::ecode::ECode; -use crate::il::instruction::{Instruction, InstructionFull}; -use crate::il::pcode::PCode; - use crate::error::Error; - use crate::float_format::FloatFormat; - -use crate::compiler; -use crate::convention::Convention; - +use crate::il::instruction::{Instruction, InstructionFull}; use crate::register::RegisterNames; use crate::space_manager::SpaceManager; @@ -271,7 +261,7 @@ impl Translator { } Some(Symbol::UserOp { index, name, .. }) => { if user_ops.len() <= *index { - user_ops.resize_with(index + 1, || Ustr::from("")); + user_ops.resize_with(index + 1, Ustr::default); } user_ops[*index] = name.clone(); } @@ -281,7 +271,7 @@ impl Translator { if let Some((pc_offset, pc_size)) = pc { self.program_counter.offset = pc_offset; - self.program_counter.size = pc_size; + self.program_counter.size = pc_size as _; } else { return Err(DeserialiseError::Invariant( "program counter not defined as a register", @@ -426,31 +416,6 @@ impl Translator { self.disassemble_with(db, &mut ctxt, &arena, builder, address, bytes) } - pub fn disassemble_cached_with<'a, 'az, 'z>( - &'a self, - db: &mut ContextDatabase, - context: &mut ParserContext<'a, 'az>, - arena: &'az IRBuilderArena, - builder: &'z IRBuilderArena, - cache: &mut Map<[u8; 2], Instruction<'z>>, - address: AddressValue, - bytes: &[u8], - ) -> Result, Error> { - if bytes.len() >= 2 { - if let Some(insn) = cache.get(&bytes[..2]) { - return Ok(insn.clone()); - } - } - - match self.disassemble_with(db, context, arena, builder, address, bytes) { - Ok(insn) if insn.length() == 2 => { - cache.insert(<[u8; 2]>::try_from(&bytes[..2]).unwrap(), insn.clone()); - Ok(insn) - } - r => r, - } - } - pub fn disassemble_aux<'a, 'az, 'c, T, E, F>( &'a self, db: &mut ContextDatabase, @@ -545,7 +510,7 @@ impl Translator { }) } - pub fn lift_pcode_raw<'z>( + pub fn lift<'z>( &self, db: &mut ContextDatabase, builder: &'z IRBuilderArena, @@ -555,10 +520,10 @@ impl Translator { let arena = IRBuilderArena::with_capacity(1024); let mut context = ParserContext::empty(&arena, self.manager()); let mut base = builder.builder(self); - self.lift_pcode_raw_with(db, &mut context, &arena, &mut base, address, bytes) + self.lift_with(db, &mut context, &arena, &mut base, address, bytes) } - pub fn lift_pcode_raw_with<'a, 'az, 'z>( + pub fn lift_with<'a, 'az, 'z>( &'a self, db: &mut ContextDatabase, context: &mut ParserContext<'a, 'az>, @@ -628,189 +593,12 @@ impl Translator { IRBuilder::new(builder, ParserWalker::new(context), &mut delay_contexts); builder.build(tmpl, None, &self.symbol_table)?; builder.resolve_relatives()?; - Ok(builder.emit_raw(fall_offset)) + Ok(builder.emit(fall_offset)) } else { Ok(PCodeRaw::nop_in(builder.arena(), address, walker.length())) } } - pub fn lift_pcode( - &self, - db: &mut ContextDatabase, - address: AddressValue, - bytes: &[u8], - ) -> Result { - let arena = IRBuilderArena::with_capacity(4096); - let mut context = ParserContext::empty(&arena, self.manager()); - self.lift_pcode_with(db, &mut context, &arena, address, bytes) - } - - pub fn lift_pcode_with<'a, 'az>( - &'a self, - db: &mut ContextDatabase, - context: &mut ParserContext<'a, 'az>, - arena: &'az IRBuilderArena, - address: AddressValue, - bytes: &[u8], - ) -> Result { - if self.alignment != 1 { - if address.offset() % self.alignment as u64 != 0 { - return Err(DisassemblyError::IncorrectAlignment { - address: address.offset(), - alignment: self.alignment, - })?; - } - } - - // Main instruction - // Parse the pcode of the current instruction - - context.reinitialise(arena, db, address.clone(), bytes); - let mut walker = ParserWalker::new(context); - - Translator::resolve(&mut walker, self.root.id(), &self.symbol_table)?; - Translator::resolve_handles(&mut walker, &self.manager, &self.symbol_table)?; - - walker.base_state(); - walker.apply_commits(db, &self.manager, &self.symbol_table)?; - - let mut fall_offset = walker.length(); - - let delay_slots = walker.delay_slot(); - let mut delay_contexts = Map::default(); - - if delay_slots > 0 { - let mut byte_count = 0; - loop { - let mut dcontext = ParserContext::new( - arena, - db, - address.clone() + fall_offset, - &bytes[fall_offset..], - ); - let mut dwalker = ParserWalker::new(&mut dcontext); - - Translator::resolve(&mut dwalker, self.root.id(), &self.symbol_table)?; - Translator::resolve_handles(&mut dwalker, &self.manager, &self.symbol_table)?; - - dwalker.base_state(); - dwalker.apply_commits(db, &self.manager, &self.symbol_table)?; - - let length = dwalker.length(); - - delay_contexts.insert(address.clone() + fall_offset, dcontext); - - fall_offset += length; - byte_count += length; - - if byte_count >= delay_slots { - break; - } - } - walker.set_next_address(address.clone() + fall_offset); - } - - if let Some(ctor) = walker.constructor()? { - let tmpl = ctor.unchecked_template(); - let mut base = arena.builder(self); - let mut builder = - IRBuilder::new(&mut base, ParserWalker::new(context), &mut delay_contexts); - builder.build(tmpl, None, &self.symbol_table)?; - builder.resolve_relatives()?; - Ok(builder.emit_pcode(fall_offset)) - } else { - Ok(PCode::nop(address, walker.length())) - } - } - - pub fn lift_ecode( - &self, - db: &mut ContextDatabase, - address: AddressValue, - bytes: &[u8], - ) -> Result { - let arena = IRBuilderArena::with_capacity(1024); - let mut context = ParserContext::empty(&arena, self.manager()); - self.lift_ecode_with(db, &mut context, &arena, address, bytes) - } - - pub fn lift_ecode_with<'a, 'az>( - &'a self, - db: &mut ContextDatabase, - context: &mut ParserContext<'a, 'az>, - arena: &'az IRBuilderArena, - address: AddressValue, - bytes: &[u8], - ) -> Result { - if self.alignment != 1 { - if address.offset() % self.alignment as u64 != 0 { - return Err(DisassemblyError::IncorrectAlignment { - address: address.offset(), - alignment: self.alignment, - })?; - } - } - - // Main instruction - // let mut context = ParserContext::new(db, address.clone(), bytes); - context.reinitialise(arena, db, address.clone(), bytes); - let mut walker = ParserWalker::new(context); - - Translator::resolve(&mut walker, self.root.id(), &self.symbol_table)?; - Translator::resolve_handles(&mut walker, &self.manager, &self.symbol_table)?; - - walker.base_state(); - walker.apply_commits(db, &self.manager, &self.symbol_table)?; - - let mut fall_offset = walker.length(); - - let delay_slots = walker.delay_slot(); - let mut delay_contexts = Map::default(); - - if delay_slots > 0 { - let mut byte_count = 0; - loop { - let mut dcontext = ParserContext::new( - arena, - db, - address.clone() + fall_offset, - &bytes[fall_offset..], - ); - let mut dwalker = ParserWalker::new(&mut dcontext); - - Translator::resolve(&mut dwalker, self.root.id(), &self.symbol_table)?; - Translator::resolve_handles(&mut dwalker, &self.manager, &self.symbol_table)?; - - dwalker.base_state(); - dwalker.apply_commits(db, &self.manager, &self.symbol_table)?; - - let length = dwalker.length(); - - delay_contexts.insert(address.clone() + fall_offset, dcontext); - - fall_offset += length; - byte_count += length; - - if byte_count >= delay_slots { - break; - } - } - walker.set_next_address(address.clone() + fall_offset); - } - - if let Some(ctor) = walker.constructor()? { - let tmpl = ctor.unchecked_template(); - let mut base = arena.builder(self); - let mut builder = - IRBuilder::new(&mut base, ParserWalker::new(context), &mut delay_contexts); - builder.build(tmpl, None, &self.symbol_table)?; - builder.resolve_relatives()?; - Ok(builder.emit_ecode(fall_offset)) - } else { - Ok(ECode::nop(address, walker.length())) - } - } - fn resolve_handles<'b, 'c, 'z>( walker: &mut ParserWalker<'b, 'c, 'z>, manager: &'b SpaceManager, @@ -951,9 +739,10 @@ mod test { let bytes = [0x20, 0xf8, 0x48, 0x4f]; let mut db = translator.context_database(); + let irb = IRBuilderArena::with_capacity(4096); let addr = translator.address(0x10cbe0u64); - let _insn = translator.lift_pcode(&mut db, addr, &bytes)?; + let _insn = translator.lift(&mut db, &irb, addr, &bytes)?; Ok(()) } @@ -1005,7 +794,7 @@ mod test { let addr = translator.address(0x0u64); let mut offset = 0; while offset < bytes.len() { - let insn = translator.lift_pcode_raw(&mut db, &irb, addr + offset, &bytes[offset..])?; + let insn = translator.lift(&mut db, &irb, addr + offset, &bytes[offset..])?; println!("{}", insn.display(&translator)); offset += insn.length(); } @@ -1014,7 +803,7 @@ mod test { let addr = translator.address(0xb000u64); let mut offset = 0; while offset < bytes.len() { - let insn = translator.lift_pcode_raw(&mut db, &irb, addr + offset, &bytes[offset..])?; + let insn = translator.lift(&mut db, &irb, addr + offset, &bytes[offset..])?; println!("{}", insn.display(&translator)); offset += insn.length(); } @@ -1040,7 +829,7 @@ mod test { let addr = translator.address(0xd92u64); let mut offset = 0; while offset < bytes.len() { - let insn = translator.lift_pcode_raw(&mut db, &irb, addr + offset, &bytes[offset..])?; + let insn = translator.lift(&mut db, &irb, addr + offset, &bytes[offset..])?; println!("{}", insn.display(&translator)); offset += insn.length(); } diff --git a/fugue-state/src/pcode.rs b/fugue-state/src/pcode.rs index 9402030..d99aac5 100644 --- a/fugue-state/src/pcode.rs +++ b/fugue-state/src/pcode.rs @@ -4,8 +4,7 @@ use std::sync::Arc; use fugue_bytes::{ByteCast, Order}; use fugue_ir::convention::Convention; -use fugue_ir::il::pcode::Operand; -use fugue_ir::{Address, AddressSpace, Translator}; +use fugue_ir::{Address, AddressSpace, Translator, VarnodeData}; use thiserror::Error; @@ -13,8 +12,8 @@ use crate::paged::{self, PagedState}; use crate::register::{self, RegisterState}; use crate::unique::{self, UniqueState}; -use crate::traits::{State, StateOps, StateValue}; use crate::traits::{FromStateValues, IntoStateValues}; +use crate::traits::{State, StateOps, StateValue}; pub const POINTER_8_SIZE: usize = 1; pub const POINTER_16_SIZE: usize = 2; @@ -102,87 +101,99 @@ impl PCodeState { &mut self.temporaries } - pub fn with_operand_values(&self, operand: &Operand, f: F) -> Result - where F: FnOnce(&[T]) -> U { - match operand { - Operand::Address { value, size } => { - self.memory() - .view_values(value.offset(), *size) - .map_err(Error::Memory) - .map(f) - }, - Operand::Constant { value, size, .. } => { - // max size of value - let mut values: [T; 8] = Default::default(); - - if O::ENDIAN.is_big() { - for (d, s) in values[..*size].iter_mut().zip(&value.to_be_bytes()[8-*size..]) { - *d = T::from_byte(*s); - } - } else { - for (d, s) in values[..*size].iter_mut().zip(&value.to_le_bytes()[..*size]) { - *d = T::from_byte(*s); - } - } + pub fn with_operand_values(&self, operand: &VarnodeData, f: F) -> Result + where + F: FnOnce(&[T]) -> U, + { + let value = operand.offset(); + let size = operand.size(); - Ok(f(&values[..*size])) - }, - Operand::Register { offset, size, .. } => { - self.registers() - .view_values(*offset, *size) - .map_err(Error::Register) - .map(f) - }, - Operand::Variable { offset, size, .. } => { - self.temporaries() - .view_values(*offset, *size) - .map_err(Error::Temporary) - .map(f) - }, + let space = operand.space(); + + if space.is_constant() { + // max size of value + let mut values: [T; 8] = Default::default(); + + if O::ENDIAN.is_big() { + for (d, s) in values[..size] + .iter_mut() + .zip(&value.to_be_bytes()[8 - size..]) + { + *d = T::from_byte(*s); + } + } else { + for (d, s) in values[..size].iter_mut().zip(&value.to_le_bytes()[..size]) { + *d = T::from_byte(*s); + } + } + + Ok(f(&values[..size])) + } else if space.is_register() { + self.registers() + .view_values(value, size) + .map_err(Error::Register) + .map(f) + } else if space.is_unique() { + self.temporaries() + .view_values(value, size) + .map_err(Error::Temporary) + .map(f) + } else { + self.memory() + .view_values(value, size) + .map_err(Error::Memory) + .map(f) } } - pub fn with_operand_values_mut(&mut self, operand: &Operand, f: F) -> Result - where F: FnOnce(&mut [T]) -> U { - match operand { - Operand::Address { value, size } => { - self.memory_mut() - .view_values_mut(value.offset(), *size) - .map_err(Error::Memory) - .map(f) - }, - Operand::Register { offset, size, .. } => { - self.registers_mut() - .view_values_mut(*offset, *size) - .map_err(Error::Register) - .map(f) - }, - Operand::Variable { offset, size, .. } => { - self.temporaries_mut() - .view_values_mut(*offset, *size) - .map_err(Error::Temporary) - .map(f) - }, - Operand::Constant { .. } => { - panic!("cannot mutate Operand::Constant"); - }, + pub fn with_operand_values_mut(&mut self, operand: &VarnodeData, f: F) -> Result + where + F: FnOnce(&mut [T]) -> U, + { + let value = operand.offset(); + let size = operand.size(); + + let space = operand.space(); + + if space.is_constant() { + panic!("cannot mutate constant operand"); + } else if space.is_register() { + self.registers_mut() + .view_values_mut(value, size) + .map_err(Error::Register) + .map(f) + } else if space.is_unique() { + self.temporaries_mut() + .view_values_mut(value, size) + .map_err(Error::Temporary) + .map(f) + } else { + self.memory_mut() + .view_values_mut(value, size) + .map_err(Error::Memory) + .map(f) } } - pub fn get_operand>(&self, operand: &Operand) -> Result { + pub fn get_operand>(&self, operand: &VarnodeData) -> Result { let res = self.with_operand_values(operand, |values| V::from_values::(values)); res } - pub fn set_operand>(&mut self, operand: &Operand, value: V) -> Result<(), Error> { + pub fn set_operand>( + &mut self, + operand: &VarnodeData, + value: V, + ) -> Result<(), Error> { self.with_operand_values_mut(operand, |values| value.into_values::(values)) } #[inline(always)] pub fn view_values_from(&self, address: A) -> Result<&[T], Error> - where A: Into
{ - self.memory.view_values_from(address) - .map_err(Error::Memory) + where + A: Into
, + { + self.memory.view_values_from(address).map_err(Error::Memory) } } @@ -196,15 +207,16 @@ impl PCodeState { } pub fn get_pointer(&self, address: Address) -> Result { - let opnd = Operand::Address { - value: address, - size: self.memory_space_ref().address_size(), - }; + let opnd = VarnodeData::new( + self.memory_space_ref(), + address.offset(), + self.memory_space_ref().address_size(), + ); self.get_address(&opnd) } // get value at address - pub fn get_address(&self, operand: &Operand) -> Result { + pub fn get_address(&self, operand: &VarnodeData) -> Result { let mut buf = [0u8; MAX_POINTER_SIZE]; let size = operand.size(); @@ -229,25 +241,30 @@ impl PCodeState { u8::from_bytes::(values) as u64 }) } else { - return Err(Error::UnsupportedAddressSize(size)) + return Err(Error::UnsupportedAddressSize(size)); }?; Ok(Address::new(self.memory.address_space_ref(), address)) } pub fn set_program_counter_value(&mut self, value: A) -> Result<(), Error> - where A: Into
{ + where + A: Into
, + { self.set_address(&self.registers.program_counter(), value) } pub fn set_stack_pointer_value(&mut self, value: A) -> Result<(), Error> - where A: Into
{ + where + A: Into
, + { self.set_address(&self.registers.stack_pointer(), value) } - pub fn set_address(&mut self, operand: &Operand, value: A) -> Result<(), Error> - where A: Into
{ - + pub fn set_address(&mut self, operand: &VarnodeData, value: A) -> Result<(), Error> + where + A: Into
, + { let size = operand.size(); let address = value.into(); @@ -268,7 +285,7 @@ impl PCodeState { u8::from(address).into_bytes::(values) }) } else { - return Err(Error::UnsupportedAddressSize(size)) + return Err(Error::UnsupportedAddressSize(size)); }?; Ok(()) @@ -300,37 +317,56 @@ impl StateOps for PCodeState { #[inline(always)] fn copy_values(&mut self, from: F, to: T, size: usize) -> Result<(), Self::Error> - where F: Into
, - T: Into
{ - self.memory.copy_values(from, to, size) + where + F: Into
, + T: Into
, + { + self.memory + .copy_values(from, to, size) .map_err(Error::Memory) } #[inline(always)] fn get_values(&self, address: A, values: &mut [Self::Value]) -> Result<(), Self::Error> - where A: Into
{ - self.memory.get_values(address, values) + where + A: Into
, + { + self.memory + .get_values(address, values) .map_err(Error::Memory) } #[inline(always)] fn view_values(&self, address: A, size: usize) -> Result<&[Self::Value], Self::Error> - where A: Into
{ - self.memory.view_values(address, size) + where + A: Into
, + { + self.memory + .view_values(address, size) .map_err(Error::Memory) } #[inline(always)] - fn view_values_mut(&mut self, address: A, size: usize) -> Result<&mut [Self::Value], Self::Error> - where A: Into
{ - self.memory.view_values_mut(address, size) + fn view_values_mut( + &mut self, + address: A, + size: usize, + ) -> Result<&mut [Self::Value], Self::Error> + where + A: Into
, + { + self.memory + .view_values_mut(address, size) .map_err(Error::Memory) } #[inline(always)] fn set_values(&mut self, address: A, values: &[Self::Value]) -> Result<(), Self::Error> - where A: Into
{ - self.memory.set_values(address, values) + where + A: Into
, + { + self.memory + .set_values(address, values) .map_err(Error::Memory) } diff --git a/fugue-state/src/register.rs b/fugue-state/src/register.rs index 25d8dac..7075a20 100644 --- a/fugue-state/src/register.rs +++ b/fugue-state/src/register.rs @@ -4,32 +4,26 @@ use std::sync::Arc; use fugue_bytes::Order; use fugue_ir::convention::{Convention, ReturnAddress}; -use fugue_ir::il::pcode::{Operand, Register}; use fugue_ir::register::RegisterNames; -use fugue_ir::{Address, Translator}; +use fugue_ir::{Address, AddressSpace, Translator, VarnodeData}; -use crate::{FromStateValues, IntoStateValues, State, StateOps, StateValue}; use crate::flat::FlatState; +use crate::{FromStateValues, IntoStateValues, State, StateOps, StateValue}; pub use crate::flat::Error; -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ReturnLocation { - Register(Operand), - Relative(Operand, u64), + Register(VarnodeData), + Relative(VarnodeData, u64), } impl ReturnLocation { - pub fn from_convention(translator: &Translator, convention: &Convention) -> Self { + pub fn from_convention(convention: &Convention) -> Self { match convention.return_address() { - ReturnAddress::Register { varnode, .. } => { - Self::Register(Operand::from_varnode(translator, *varnode)) - }, + ReturnAddress::Register { varnode, .. } => Self::Register(*varnode), ReturnAddress::StackRelative { offset, .. } => { - Self::Relative( - Operand::from_varnode(translator, *convention.stack_pointer().varnode()), - *offset, - ) + Self::Relative(*convention.stack_pointer().varnode(), *offset) } } } @@ -37,10 +31,10 @@ impl ReturnLocation { #[derive(Debug, Clone)] pub struct RegisterState { - program_counter: Arc, - stack_pointer: Arc, + program_counter: VarnodeData, + stack_pointer: VarnodeData, register_names: Arc, - return_location: Arc, + return_location: ReturnLocation, inner: FlatState, marker: PhantomData, } @@ -124,41 +118,55 @@ impl StateOps for RegisterState { #[inline(always)] fn copy_values(&mut self, from: F, to: T, size: usize) -> Result<(), Self::Error> - where F: Into
, - T: Into
{ + where + F: Into
, + T: Into
, + { self.inner.copy_values(from, to, size) } #[inline(always)] fn get_values(&self, address: A, bytes: &mut [Self::Value]) -> Result<(), Self::Error> - where A: Into
{ + where + A: Into
, + { self.inner.get_values(address, bytes) } #[inline(always)] fn view_values(&self, address: A, size: usize) -> Result<&[Self::Value], Self::Error> - where A: Into
{ + where + A: Into
, + { self.inner.view_values(address, size) } #[inline(always)] - fn view_values_mut(&mut self, address: A, size: usize) -> Result<&mut [Self::Value], Self::Error> - where A: Into
{ + fn view_values_mut( + &mut self, + address: A, + size: usize, + ) -> Result<&mut [Self::Value], Self::Error> + where + A: Into
, + { self.inner.view_values_mut(address, size) } #[inline(always)] fn set_values(&mut self, address: A, bytes: &[Self::Value]) -> Result<(), Self::Error> - where A: Into
{ + where + A: Into
, + { self.inner.set_values(address, bytes) } } impl RegisterState { pub fn new(translator: &Translator, convention: &Convention) -> Self { - let program_counter = Arc::new(Operand::from_varnode(translator, *translator.program_counter())); - let stack_pointer = Arc::new(Operand::from_varnode(translator, *convention.stack_pointer().varnode())); - let return_location = Arc::new(ReturnLocation::from_convention(translator, convention)); + let program_counter = *translator.program_counter(); + let stack_pointer = *convention.stack_pointer().varnode(); + let return_location = ReturnLocation::from_convention(convention); let space = translator.manager().register_space(); let register_names = translator.registers().clone(); @@ -176,19 +184,23 @@ impl RegisterState { } } - pub fn program_counter(&self) -> Arc { - self.program_counter.clone() + pub fn program_counter(&self) -> VarnodeData { + self.program_counter } - pub fn stack_pointer(&self) -> Arc { - self.stack_pointer.clone() + pub fn stack_pointer(&self) -> VarnodeData { + self.stack_pointer } - pub fn return_location(&self) -> Arc { - self.return_location.clone() + pub fn return_location(&self) -> ReturnLocation { + self.return_location } - pub fn get_register_values(&self, register: &Register, values: &mut [T]) -> Result<(), Error> { + pub fn get_register_values( + &self, + register: &VarnodeData, + values: &mut [T], + ) -> Result<(), Error> { let view = self.view_values(register.offset(), register.size())?; values.clone_from_slice(view); Ok(()) @@ -198,25 +210,41 @@ impl RegisterState { &self.register_names } - pub fn register_by_name(&self, name: N) -> Option - where N: AsRef { + pub fn register_by_name(&self, name: N) -> Option + where + N: AsRef, + { self.register_names .get_by_name(name) - .map(|(name, offset, size)| Register::new(name.clone(), offset, size)) + .map(|(_name, offset, size)| VarnodeData::new(self.space_ref(), offset, size)) } - pub fn get_register>(&self, register: &Register) -> Result { - Ok(V::from_values::(self.view_values(register.offset(), register.size())?)) + pub fn get_register>(&self, register: &VarnodeData) -> Result { + Ok(V::from_values::( + self.view_values(register.offset(), register.size())?, + )) } - pub fn set_register_values(&mut self, register: &Register, values: &[T]) -> Result<(), Error> { + pub fn set_register_values( + &mut self, + register: &VarnodeData, + values: &[T], + ) -> Result<(), Error> { let view = self.view_values_mut(register.offset(), register.size())?; view.clone_from_slice(values); Ok(()) } - pub fn set_register>(&mut self, register: &Register, value: V) -> Result<(), Error> { + pub fn set_register>( + &mut self, + register: &VarnodeData, + value: V, + ) -> Result<(), Error> { value.into_values::(self.view_values_mut(register.offset(), register.size())?); Ok(()) } + + pub fn space_ref(&self) -> &AddressSpace { + self.inner.address_space_ref() + } } diff --git a/fugue-state/src/traits.rs b/fugue-state/src/traits.rs index 5d3533e..58ed0d6 100644 --- a/fugue-state/src/traits.rs +++ b/fugue-state/src/traits.rs @@ -1,6 +1,6 @@ use fugue_bv::BitVec; -use fugue_bytes::Order; use fugue_bytes::traits::ByteCast; +use fugue_bytes::Order; use fugue_ir::Address; use paste::paste; @@ -11,7 +11,10 @@ pub trait StateValue: Clone + Default { fn from_byte(value: u8) -> Self; } -impl StateValue for V where V: Clone + Default + From { +impl StateValue for V +where + V: Clone + Default + From, +{ #[inline(always)] fn from_byte(value: u8) -> Self { Self::from(value) @@ -94,20 +97,29 @@ pub trait StateOps: State { fn len(&self) -> usize; fn copy_values(&mut self, from: F, to: T, size: usize) -> Result<(), Self::Error> - where F: Into
, - T: Into
; + where + F: Into
, + T: Into
; fn get_values(&self, address: A, bytes: &mut [Self::Value]) -> Result<(), Self::Error> - where A: Into
; + where + A: Into
; fn view_values(&self, address: A, size: usize) -> Result<&[Self::Value], Self::Error> - where A: Into
; + where + A: Into
; - fn view_values_mut(&mut self, address: A, size: usize) -> Result<&mut [Self::Value], Self::Error> - where A: Into
; + fn view_values_mut( + &mut self, + address: A, + size: usize, + ) -> Result<&mut [Self::Value], Self::Error> + where + A: Into
; fn set_values(&mut self, address: A, bytes: &[Self::Value]) -> Result<(), Self::Error> - where A: Into
; + where + A: Into
; } pub trait AsState: State { @@ -115,7 +127,10 @@ pub trait AsState: State { fn state_mut(&mut self) -> &mut S; } -impl AsState for T where T: State + AsRef + AsMut { +impl AsState for T +where + T: State + AsRef + AsMut, +{ fn state_ref(&self) -> &S { self.as_ref() } @@ -143,7 +158,12 @@ pub trait AsState3: State + AsState + AsState + AsState { pub trait AsState4: State + AsState + AsState + AsState + AsState { fn state4_ref(&self) -> (&S, &T, &U, &V) { - (self.state_ref(), self.state_ref(), self.state_ref(), self.state_ref()) + ( + self.state_ref(), + self.state_ref(), + self.state_ref(), + self.state_ref(), + ) } fn state4_mut(&mut self) -> (&mut S, &mut T, &mut U, &mut V);