1
0
Fork 0
fayalite/crates/fayalite/src/expr/ops.rs
Jacob Lifshay 5c594cbb68
reimplement fayalite::formal and add support to the simulator
Add support to the simulator for running hdl asserts/assumes and being
able to write to the formal global clock/reset and all any/all_const/seq that are used.
This allows you to use the exact same HDL code for running a simulation and for running a formal proof.
2026-06-05 00:46:30 -07:00

4945 lines
154 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::{Array, ArrayType},
bundle::{Bundle, BundleField, BundleType},
clock::{Clock, ToClock},
enum_::{Enum, EnumType, EnumVariant},
expr::{
CastBitsTo as _, CastTo, CastToBits as _, CastToImpl, Expr, ExprEnum, Flow, HdlPartialEq,
HdlPartialEqImpl, HdlPartialOrd, HdlPartialOrdImpl, NotALiteralExpr, ReduceBitsImpl,
ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless,
target::{
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
value_category::ValueCategoryExpr,
},
formal::FormalInput,
int::{
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
UIntType, UIntValue,
},
intern::{Intern, Interned},
phantom_const::{PhantomConst, PhantomConstValue},
reset::{
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
ToSyncReset,
},
sim::value::{SimValue, ToSimValue},
ty::{CanonicalType, StaticType, TraceAsString, Type},
util::ConstUsize,
};
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
use num_bigint::BigInt;
use num_traits::{ToPrimitive, Zero};
use std::{
borrow::Cow,
fmt,
marker::PhantomData,
num::NonZero,
ops::{
Add, BitAnd, BitOr, BitXor, Div, Index, Mul, Neg as StdNeg, Not, Range, RangeBounds, Rem,
Shl, Shr, Sub,
},
};
#[cfg(test)]
mod test_ops_impls;
macro_rules! make_impls {
(
$([$($args:tt)*])?
$m:ident! {$($rest:tt)*}
) => {
$m! {$($($args)*)? $($rest)*}
};
(
#[kinds()]
$($rest:tt)*
) => {};
(
#[kinds($first_kind:tt $(, $kinds:tt)* $(,)?)]
$($rest:tt)*
) => {
make_impls! {
#[kind($first_kind)]
$($rest)*
}
make_impls! {
#[kinds($($kinds),*)]
$($rest)*
}
};
(
#[type($($ty:tt)*)]
$(#[$($meta:tt)*])*
$([$($args:tt)*])?
$m:ident $($rest:tt)*
) => {
make_impls! {
$(#[$($meta)*])*
[$($($args)*)? $($ty)*,]
$m $($rest)*
}
};
(
#[kind((int_no_nz<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds((uint_no_nz<$lt, $Width>), (sint_no_nz<$lt, $Width>))]
$($rest)*
}
};
(
#[kind((int_local<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds((uint_local<$lt, $Width>), (sint_local<$lt, $Width>))]
$($rest)*
}
};
(
#[kind((int_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds((uint_value<$lt, $Width>), (sint_value<$lt, $Width>))]
$($rest)*
}
};
(
#[kind((int_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds((uint_sim_value<$lt, $Width>), (sint_sim_value<$lt, $Width>))]
$($rest)*
}
};
(
#[kind((uint<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(NonZero<usize>),
NonZeroU_N,
(uint_no_nz<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((sint<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(NonZero<isize>),
NonZeroI_N,
(sint_no_nz<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((uint_no_nz<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
usize,
u_N,
(uint_value<$lt, $Width>),
(uint_sim_value<$lt, $Width>),
(Expr<UIntType<$Width: Size>>),
(Valueless<UIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((sint_no_nz<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
isize,
i_N,
(sint_value<$lt, $Width>),
(sint_sim_value<$lt, $Width>),
(Expr<SIntType<$Width: Size>>),
(Valueless<SIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((uint_at_most_expr<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(uint_at_most_sim_value<$lt, $Width>),
(Expr<UIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((sint_at_most_expr<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(sint_at_most_sim_value<$lt, $Width>),
(Expr<SIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((uint_at_most_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(uint_at_most_value<$lt, $Width>),
(uint_sim_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((sint_at_most_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(sint_at_most_value<$lt, $Width>),
(sint_sim_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((uint_local_at_most_expr<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(uint_local_at_most_sim_value<$lt, $Width>),
(Expr<UIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((sint_local_at_most_expr<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(sint_local_at_most_sim_value<$lt, $Width>),
(Expr<SIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((uint_local_at_most_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(uint_value<$lt, $Width>),
(uint_sim_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((sint_local_at_most_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(sint_value<$lt, $Width>),
(sint_sim_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((uint_at_most_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
prim_uint,
(uint_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind((sint_at_most_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
prim_sint,
(sint_value<$lt, $Width>),
)]
$($rest)*
}
};
(
#[kind(prim_uint)]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(NonZero<usize>),
NonZeroU_N,
usize,
u_N,
)]
$($rest)*
}
};
(
#[kind(prim_sint)]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(NonZero<isize>),
NonZeroI_N,
isize,
i_N,
)]
$($rest)*
}
};
(
#[kind((bool_local_at_most_expr<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(bool_sim_value<$lt>),
(Expr<Bool>),
)]
$($rest)*
}
};
(
#[kind((bool_at_most_expr<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(bool_at_most_sim_value<$lt>),
(Expr<Bool>),
)]
$($rest)*
}
};
(
#[kind((bool_at_most_sim_value<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
bool,
(bool_sim_value<$lt>),
)]
$($rest)*
}
};
(
#[kind((uint_local<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(uint_value<$lt, $Width>),
(SimValue<UIntType<$Width: Size>>),
(&$lt SimValue<UIntType<$Width: Size>>),
(Expr<UIntType<$Width: Size>>),
(Valueless<UIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((sint_local<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(sint_value<$lt, $Width>),
(SimValue<SIntType<$Width: Size>>),
(&$lt SimValue<SIntType<$Width: Size>>),
(Expr<SIntType<$Width: Size>>),
(Valueless<SIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((uint_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(UIntValue<$Width: Size>),
(&$lt UIntValue<$Width: Size>),
)]
$($rest)*
}
};
(
#[kind((sint_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(SIntValue<$Width: Size>),
(&$lt SIntValue<$Width: Size>),
)]
$($rest)*
}
};
(
#[kind((uint_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(SimValue<UIntType<$Width: Size>>),
(&$lt SimValue<UIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((sint_sim_value<$lt:lifetime, $Width:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(SimValue<SIntType<$Width: Size>>),
(&$lt SimValue<SIntType<$Width: Size>>),
)]
$($rest)*
}
};
(
#[kind((bool_sim_value<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(SimValue<Bool>),
(&$lt SimValue<Bool>),
)]
$($rest)*
}
};
(
#[kind((bool<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
bool,
(bool_sim_value<$lt>),
(Expr<Bool>),
(Valueless<Bool>),
)]
$($rest)*
}
};
(
#[kind((bool_local<$lt:lifetime>))]
$($rest:tt)*
) => {
make_impls! {
#[kinds(
(bool_sim_value<$lt>),
(Expr<Bool>),
(Valueless<Bool>),
)]
$($rest)*
}
};
(
#[kind(u_N)]
$($rest:tt)*
) => {
make_impls! {
#[kinds(u8, u16, u32, u64, u128)]
$($rest)*
}
};
(
#[kind(i_N)]
$($rest:tt)*
) => {
make_impls! {
#[kinds(i8, i16, i32, i64, i128)]
$($rest)*
}
};
(
#[kind(NonZeroU_N)]
$($rest:tt)*
) => {
make_impls! {
#[kinds((NonZero<u8>), (NonZero<u16>), (NonZero<u32>), (NonZero<u64>), (NonZero<u128>))]
$($rest)*
}
};
(
#[kind(NonZeroI_N)]
$($rest:tt)*
) => {
make_impls! {
#[kinds((NonZero<i8>), (NonZero<i16>), (NonZero<i32>), (NonZero<i64>), (NonZero<i128>))]
$($rest)*
}
};
(
#[kind(($wrapper:ident<$Ty:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[type([][] ($wrapper<$Ty>))]
$($rest)*
}
};
(
#[kind((&$lt:lifetime $wrapper:ident<$Ty:ident>))]
$($rest:tt)*
) => {
make_impls! {
#[type([$lt,][] (&$lt $wrapper<$Ty>))]
$($rest)*
}
};
(
#[kind(($wrapper:ident<$Width:ident: Size>))]
$($rest:tt)*
) => {
make_impls! {
#[type([][$Width: Size,] ($wrapper<$Width>))]
$($rest)*
}
};
(
#[kind(($wrapper:ident<$ty:ident<$Width:ident: Size>>))]
$($rest:tt)*
) => {
make_impls! {
#[type([][$Width: Size,] ($wrapper<$ty<$Width>>))]
$($rest)*
}
};
(
#[kind((&$lt:lifetime $wrapper:ident<$Width:ident: Size>))]
$($rest:tt)*
) => {
make_impls! {
#[type([$lt,][$Width: Size,] (&$lt $wrapper<$Width>))]
$($rest)*
}
};
(
#[kind((&$lt:lifetime $wrapper:ident<$ty:ident<$Width:ident: Size>>))]
$($rest:tt)*
) => {
make_impls! {
#[type([$lt,][$Width: Size,] (&$lt $wrapper<$ty<$Width>>))]
$($rest)*
}
};
(#[kind(usize)] $($rest:tt)*) => {make_impls! { #[type([][] (usize))] $($rest)* }};
(#[kind(isize)] $($rest:tt)*) => {make_impls! { #[type([][] (isize))] $($rest)* }};
(#[kind(bool)] $($rest:tt)*) => {make_impls! { #[type([][] (bool))] $($rest)* }};
(#[kind(u8)] $($rest:tt)*) => {make_impls! { #[type([][] (u8))] $($rest)* }};
(#[kind(u16)] $($rest:tt)*) => {make_impls! { #[type([][] (u16))] $($rest)* }};
(#[kind(u32)] $($rest:tt)*) => {make_impls! { #[type([][] (u32))] $($rest)* }};
(#[kind(u64)] $($rest:tt)*) => {make_impls! { #[type([][] (u64))] $($rest)* }};
(#[kind(u128)] $($rest:tt)*) => {make_impls! { #[type([][] (u128))] $($rest)* }};
(#[kind(i8)] $($rest:tt)*) => {make_impls! { #[type([][] (i8))] $($rest)* }};
(#[kind(i16)] $($rest:tt)*) => {make_impls! { #[type([][] (i16))] $($rest)* }};
(#[kind(i32)] $($rest:tt)*) => {make_impls! { #[type([][] (i32))] $($rest)* }};
(#[kind(i64)] $($rest:tt)*) => {make_impls! { #[type([][] (i64))] $($rest)* }};
(#[kind(i128)] $($rest:tt)*) => {make_impls! { #[type([][] (i128))] $($rest)* }};
}
#[cfg(test)]
pub(crate) use make_impls;
macro_rules! impl_simple_binary_op_trait {
(
[$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*),
[$($RLifetimes:tt)*][$($RBounds:tt)*] ($($R:tt)*),
$(#[$meta:meta])*
$Trait:ident::$f:ident($f_self:ident, $f_rhs:ident) -> $Out:ident<_> $body:block $(,)?
) => {
$(#[$meta])*
impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*> $Trait<$($R)*> for $($L)* {
type Output = $Out<<<Valueless<<$($L)* as ValueType>::Type> as $Trait<Valueless<<$($R)* as ValueType>::Type>>>::Output as ValueType>::Type>;
fn $f($f_self, $f_rhs: $($R)*) -> Self::Output $body
}
};
(
$LLifetimes:tt $LBounds:tt ($($L:tt)*),
$RLifetimes:tt $RBounds:tt ($($R:tt)*),
$(#[$meta:meta])*
$FirstTrait:ident::$first_f:ident($f_self:ident, $f_rhs:ident) -> $Out:ident<_> $body:block,
$($rest:tt)*
) => {
impl_simple_binary_op_trait! {
$LLifetimes $LBounds ($($L)*),
$RLifetimes $RBounds ($($R)*),
$(#[$meta])*
$FirstTrait::$first_f($f_self, $f_rhs) -> $Out<_> $body
}
impl_simple_binary_op_trait! {
$LLifetimes $LBounds ($($L)*),
$RLifetimes $RBounds ($($R)*),
$(#[$meta])*
$($rest)*
}
};
}
make_impls! {
#[kinds((Expr<UIntType<L: Size>>))]
#[kinds((uint_at_most_sim_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Expr<_> {
AddU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Sub::sub(self, rhs) -> Expr<_> {
SubU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Mul::mul(self, rhs) -> Expr<_> {
MulU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Div::div(self, rhs) -> Expr<_> {
DivU::new(self.to_expr(), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Rem::rem(self, rhs) -> Expr<_> {
RemU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((Expr<SIntType<L: Size>>))]
#[kinds((sint_at_most_sim_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Expr<_> {
AddS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Sub::sub(self, rhs) -> Expr<_> {
SubS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Mul::mul(self, rhs) -> Expr<_> {
MulS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Div::div(self, rhs) -> Expr<_> {
DivS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Rem::rem(self, rhs) -> Expr<_> {
RemS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((uint_at_most_expr<'l, L>))]
#[kinds((Expr<UIntType<R: Size>>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Expr<_> {
AddU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Sub::sub(self, rhs) -> Expr<_> {
SubU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Mul::mul(self, rhs) -> Expr<_> {
MulU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Div::div(self, rhs) -> Expr<_> {
DivU::new(self.to_expr(), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Rem::rem(self, rhs) -> Expr<_> {
RemU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((sint_at_most_expr<'l, L>))]
#[kinds((Expr<SIntType<R: Size>>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Expr<_> {
AddS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Sub::sub(self, rhs) -> Expr<_> {
SubS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Mul::mul(self, rhs) -> Expr<_> {
MulS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Div::div(self, rhs) -> Expr<_> {
DivS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Rem::rem(self, rhs) -> Expr<_> {
RemS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((uint_sim_value<'l, L>))]
#[kinds((uint_at_most_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint())).into_sim_value()
},
Sub::sub(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint())).into_sim_value()
},
Mul::mul(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint())).into_sim_value()
},
Div::div(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint())).into_sim_value()
},
Rem::rem(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint())).into_sim_value()
},
BitAnd::bitand(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint())).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint())).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint())).into_sim_value()
},
}
}
make_impls! {
#[kinds((sint_sim_value<'l, L>))]
#[kinds((sint_at_most_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint())).into_sim_value()
},
Sub::sub(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint())).into_sim_value()
},
Mul::mul(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint())).into_sim_value()
},
Div::div(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint())).into_sim_value()
},
Rem::rem(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint())).into_sim_value()
},
BitAnd::bitand(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint())).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint())).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint())).into_sim_value()
},
}
}
make_impls! {
#[kinds((uint_at_most_sim_value<'l, L>))]
#[kinds((uint_sim_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint())).into_sim_value()
},
Sub::sub(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint())).into_sim_value()
},
Mul::mul(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint())).into_sim_value()
},
Div::div(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint())).into_sim_value()
},
Rem::rem(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint())).into_sim_value()
},
BitAnd::bitand(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint())).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint())).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint())).into_sim_value()
},
}
}
make_impls! {
#[kinds((sint_at_most_sim_value<'l, L>))]
#[kinds((sint_sim_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint())).into_sim_value()
},
Sub::sub(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint())).into_sim_value()
},
Mul::mul(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint())).into_sim_value()
},
Div::div(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint())).into_sim_value()
},
Rem::rem(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint())).into_sim_value()
},
BitAnd::bitand(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint())).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint())).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint())).into_sim_value()
},
}
}
make_impls! {
#[kinds((uint_at_most_expr<'l, L>))]
#[kinds((Valueless<UIntType<R: Size>>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Valueless<_> {
self.to_valueless().add(rhs.to_valueless())
},
Sub::sub(self, rhs) -> Valueless<_> {
self.to_valueless().sub(rhs.to_valueless())
},
Mul::mul(self, rhs) -> Valueless<_> {
self.to_valueless().mul(rhs.to_valueless())
},
Div::div(self, rhs) -> Valueless<_> {
self.to_valueless().div(rhs.to_valueless())
},
Rem::rem(self, rhs) -> Valueless<_> {
self.to_valueless().rem(rhs.to_valueless())
},
BitAnd::bitand(self, rhs) -> Valueless<_> {
self.to_valueless().bitand(rhs.to_valueless())
},
BitOr::bitor(self, rhs) -> Valueless<_> {
self.to_valueless().bitor(rhs.to_valueless())
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
self.to_valueless().bitxor(rhs.to_valueless())
},
}
}
make_impls! {
#[kinds((sint_at_most_expr<'l, L>))]
#[kinds((Valueless<SIntType<R: Size>>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Valueless<_> {
self.to_valueless().add(rhs.to_valueless())
},
Sub::sub(self, rhs) -> Valueless<_> {
self.to_valueless().sub(rhs.to_valueless())
},
Mul::mul(self, rhs) -> Valueless<_> {
self.to_valueless().mul(rhs.to_valueless())
},
Div::div(self, rhs) -> Valueless<_> {
self.to_valueless().div(rhs.to_valueless())
},
Rem::rem(self, rhs) -> Valueless<_> {
self.to_valueless().rem(rhs.to_valueless())
},
BitAnd::bitand(self, rhs) -> Valueless<_> {
self.to_valueless().bitand(rhs.to_valueless())
},
BitOr::bitor(self, rhs) -> Valueless<_> {
self.to_valueless().bitor(rhs.to_valueless())
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
self.to_valueless().bitxor(rhs.to_valueless())
},
}
}
make_impls! {
#[kinds((Valueless<UIntType<L: Size>>))]
#[kinds((uint_at_most_expr<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Valueless<_> {
self.to_valueless().add(rhs.to_valueless())
},
Sub::sub(self, rhs) -> Valueless<_> {
self.to_valueless().sub(rhs.to_valueless())
},
Mul::mul(self, rhs) -> Valueless<_> {
self.to_valueless().mul(rhs.to_valueless())
},
Div::div(self, rhs) -> Valueless<_> {
self.to_valueless().div(rhs.to_valueless())
},
Rem::rem(self, rhs) -> Valueless<_> {
self.to_valueless().rem(rhs.to_valueless())
},
BitAnd::bitand(self, rhs) -> Valueless<_> {
self.to_valueless().bitand(rhs.to_valueless())
},
BitOr::bitor(self, rhs) -> Valueless<_> {
self.to_valueless().bitor(rhs.to_valueless())
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
self.to_valueless().bitxor(rhs.to_valueless())
},
}
}
make_impls! {
#[kinds((Valueless<SIntType<L: Size>>))]
#[kinds((sint_at_most_expr<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> Valueless<_> {
self.to_valueless().add(rhs.to_valueless())
},
Sub::sub(self, rhs) -> Valueless<_> {
self.to_valueless().sub(rhs.to_valueless())
},
Mul::mul(self, rhs) -> Valueless<_> {
self.to_valueless().mul(rhs.to_valueless())
},
Div::div(self, rhs) -> Valueless<_> {
self.to_valueless().div(rhs.to_valueless())
},
Rem::rem(self, rhs) -> Valueless<_> {
self.to_valueless().rem(rhs.to_valueless())
},
BitAnd::bitand(self, rhs) -> Valueless<_> {
self.to_valueless().bitand(rhs.to_valueless())
},
BitOr::bitor(self, rhs) -> Valueless<_> {
self.to_valueless().bitor(rhs.to_valueless())
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
self.to_valueless().bitxor(rhs.to_valueless())
},
}
}
type SimValueInner<T> = <T as Type>::SimValue;
trait ValueIntoBigInt {
fn value_to_bigint(&self) -> BigInt;
}
macro_rules! impl_value_to_bigint {
([$($Lifetimes:tt)*][$($Bounds:tt)*] (NonZero<$T:ty>),) => {
impl<$($Lifetimes)* $($Bounds)*> ValueIntoBigInt for NonZero<$T> {
fn value_to_bigint(&self) -> BigInt {
self.get().into()
}
}
};
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($(&$lt:lifetime)? $IntValue:ident<$Width:ident>),) => {
impl<$($Lifetimes)* $($Bounds)*> ValueIntoBigInt for $(&$lt)? $IntValue<$Width> {
fn value_to_bigint(&self) -> BigInt {
self.to_bigint()
}
}
};
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($(&$lt:lifetime)? SimValue<$IntType:ident<$Width:ident>>),) => {
impl<$($Lifetimes)* $($Bounds)*> ValueIntoBigInt for $(&$lt)? SimValue<$IntType<$Width>> {
fn value_to_bigint(&self) -> BigInt {
self.to_bigint()
}
}
};
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($T:ty),) => {
impl<$($Lifetimes)* $($Bounds)*> ValueIntoBigInt for $T {
fn value_to_bigint(&self) -> BigInt {
(*self).into()
}
}
};
}
make_impls! {
#[kinds((sint_at_most_sim_value<'a, Width>), (uint_at_most_sim_value<'a, Width>))]
impl_value_to_bigint! {}
}
make_impls! {
#[kinds((uint_value<'l, L>))]
#[kinds(prim_uint)]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint()))
},
Sub::sub(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint()))
},
Mul::mul(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint()))
},
Div::div(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint()))
},
Rem::rem(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint()))
},
BitAnd::bitand(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint()))
},
BitOr::bitor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint()))
},
BitXor::bitxor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint()))
},
}
}
make_impls! {
#[kinds((sint_value<'l, L>))]
#[kinds(prim_sint)]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint()))
},
Sub::sub(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint()))
},
Mul::mul(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint()))
},
Div::div(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint()))
},
Rem::rem(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint()))
},
BitAnd::bitand(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint()))
},
BitOr::bitor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint()))
},
BitXor::bitxor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint()))
},
}
}
make_impls! {
#[kinds((uint_at_most_value<'l, L>))]
#[kinds((uint_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint()))
},
Sub::sub(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint()))
},
Mul::mul(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint()))
},
Div::div(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint()))
},
Rem::rem(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint()))
},
BitAnd::bitand(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint()))
},
BitOr::bitor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint()))
},
BitXor::bitxor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint()))
},
}
}
make_impls! {
#[kinds((sint_at_most_value<'l, L>))]
#[kinds((sint_value<'r, R>))]
impl_simple_binary_op_trait! {
Add::add(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().add(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().add(rhs.value_to_bigint()))
},
Sub::sub(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().sub(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().sub(rhs.value_to_bigint()))
},
Mul::mul(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().mul(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().mul(rhs.value_to_bigint()))
},
Div::div(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().div(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().div(rhs.value_to_bigint()))
},
Rem::rem(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().rem(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().rem(rhs.value_to_bigint()))
},
BitAnd::bitand(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitand(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitand(rhs.value_to_bigint()))
},
BitOr::bitor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitor(rhs.value_to_bigint()))
},
BitXor::bitxor(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().bitxor(rhs.to_valueless()).ty();
ty.from_int_wrapping(self.value_to_bigint().bitxor(rhs.value_to_bigint()))
},
}
}
make_impls! {
#[kinds((Expr<Bool>))]
#[kinds((bool_sim_value<'r>))]
impl_simple_binary_op_trait! {
/// intentionally only implemented for expressions, not rust's bool type,
/// since that helps avoid using `==`/`!=` in hdl boolean expressions, which doesn't do
/// what is usually wanted.
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
}
}
make_impls! {
#[kinds((bool_local_at_most_expr<'l>))]
#[kinds((Expr<Bool>))]
impl_simple_binary_op_trait! {
/// intentionally only implemented for expressions, not rust's bool type,
/// since that helps avoid using `==`/`!=` in hdl boolean expressions, which doesn't do
/// what is usually wanted.
BitAnd::bitand(self, rhs) -> Expr<_> {
BitAndB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
BitOr::bitor(self, rhs) -> Expr<_> {
BitOrB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
BitXor::bitxor(self, rhs) -> Expr<_> {
BitXorB::new(self.to_expr(), rhs.to_expr()).to_expr()
},
}
}
make_impls! {
#[kinds((bool_at_most_sim_value<'l>))]
#[kinds((bool_sim_value<'r>))]
impl_simple_binary_op_trait! {
BitAnd::bitand(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitand(*ToSimValueInner::into_sim_value_inner(rhs)).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitor(*ToSimValueInner::into_sim_value_inner(rhs)).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitxor(*ToSimValueInner::into_sim_value_inner(rhs)).into_sim_value()
},
}
}
make_impls! {
#[kinds((bool_sim_value<'l>))]
#[kinds(bool)]
impl_simple_binary_op_trait! {
BitAnd::bitand(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitand(rhs).into_sim_value()
},
BitOr::bitor(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitor(rhs).into_sim_value()
},
BitXor::bitxor(self, rhs) -> SimValue<_> {
ToSimValueInner::into_sim_value_inner(self).bitxor(rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((bool_at_most_expr<'l>))]
#[kinds((Valueless<Bool>))]
impl_simple_binary_op_trait! {
BitAnd::bitand(self, rhs) -> Valueless<_> {
rhs
},
BitOr::bitor(self, rhs) -> Valueless<_> {
rhs
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
rhs
},
}
}
make_impls! {
#[kinds((Valueless<Bool>))]
#[kinds((bool_at_most_expr<'r>))]
impl_simple_binary_op_trait! {
BitAnd::bitand(self, rhs) -> Valueless<_> {
rhs.to_valueless()
},
BitOr::bitor(self, rhs) -> Valueless<_> {
rhs.to_valueless()
},
BitXor::bitxor(self, rhs) -> Valueless<_> {
rhs.to_valueless()
},
}
}
macro_rules! impl_shift_binary_op_trait {
(
[$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*),
[][] (usize),
$(#[$meta:meta])*
$Trait:ident::$f:ident($f_self:ident, $f_rhs:ident) -> $Out:ident<_> $body:block $(,)?
) => {
$(#[$meta])*
impl<$($LLifetimes)* $($LBounds)*> $Trait<usize> for $($L)* {
type Output = $Out<<<Valueless<<$($L)* as ValueType>::Type> as $Trait<usize>>::Output as ValueType>::Type>;
#[track_caller]
fn $f($f_self, $f_rhs: usize) -> Self::Output $body
}
};
(
[$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*),
[$($RLifetimes:tt)*][$($RBounds:tt)*] ($($R:tt)*),
$(#[$meta:meta])*
$Trait:ident::$f:ident($f_self:ident, $f_rhs:ident) -> $Out:ident<_> $body:block $(,)?
) => {
$(#[$meta])*
impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*> $Trait<$($R)*> for $($L)* {
type Output = $Out<<<Valueless<<$($L)* as ValueType>::Type> as $Trait<Valueless<<$($R)* as ValueType>::Type>>>::Output as ValueType>::Type>;
#[track_caller]
fn $f($f_self, $f_rhs: $($R)*) -> Self::Output $body
}
};
(
$LLifetimes:tt $LBounds:tt ($($L:tt)*),
$RLifetimes:tt $RBounds:tt ($($R:tt)*),
$(#[$meta:meta])*
$FirstTrait:ident::$first_f:ident($f_self:ident, $f_rhs:ident) -> $Out:ident<_> $body:block,
$($rest:tt)*
) => {
impl_shift_binary_op_trait! {
$LLifetimes $LBounds ($($L)*),
$RLifetimes $RBounds ($($R)*),
$(#[$meta])*
$FirstTrait::$first_f($f_self, $f_rhs) -> $Out<_> $body
}
impl_shift_binary_op_trait! {
$LLifetimes $LBounds ($($L)*),
$RLifetimes $RBounds ($($R)*),
$(#[$meta])*
$($rest)*
}
};
}
make_impls! {
#[kinds((Expr<UIntType<L: Size>>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> Expr<_> {
FixedShlU::new(Expr::as_dyn_int(self.to_expr()), rhs).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
FixedShrU::new(Expr::as_dyn_int(self.to_expr()), rhs).to_expr()
},
}
}
make_impls! {
#[kinds((Expr<SIntType<L: Size>>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> Expr<_> {
FixedShlS::new(Expr::as_dyn_int(self.to_expr()), rhs).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
FixedShrS::new(Expr::as_dyn_int(self.to_expr()), rhs).to_expr()
},
}
}
make_impls! {
#[kinds((uint_at_most_expr<'l, L>))]
#[kinds((Expr<UIntType<R: Size>>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Expr<_> {
DynShlU::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs)).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
DynShrU::new(self.to_expr(), Expr::as_dyn_int(rhs)).to_expr()
},
}
}
make_impls! {
#[kinds((sint_at_most_expr<'l, L>))]
#[kinds((Expr<UIntType<R: Size>>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Expr<_> {
DynShlS::new(Expr::as_dyn_int(self.to_expr()), Expr::as_dyn_int(rhs)).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
DynShrS::new(self.to_expr(), Expr::as_dyn_int(rhs)).to_expr()
},
}
}
make_impls! {
#[kinds((Expr<UIntType<L: Size>>))]
#[kinds((uint_local_at_most_sim_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Expr<_> {
DynShlU::new(Expr::as_dyn_int(self), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
DynShrU::new(self, Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((Expr<SIntType<L: Size>>))]
#[kinds((uint_local_at_most_sim_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Expr<_> {
DynShlS::new(Expr::as_dyn_int(self), Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
Shr::shr(self, rhs) -> Expr<_> {
DynShrS::new(self, Expr::as_dyn_int(rhs.to_expr())).to_expr()
},
}
}
make_impls! {
#[kinds((uint_at_most_sim_value<'l, L>))]
#[kinds((uint_sim_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((sint_at_most_sim_value<'l, L>))]
#[kinds((uint_sim_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((uint_sim_value<'l, L>))]
#[kinds((uint_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((sint_sim_value<'l, L>))]
#[kinds((uint_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((uint_sim_value<'l, L>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((sint_sim_value<'l, L>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shl(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() << rhs).into_sim_value()
},
Shr::shr(self, rhs) -> SimValue<_> {
let ty = self.to_valueless().shr(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() >> rhs).into_sim_value()
},
}
}
make_impls! {
#[kinds((uint_at_most_value<'l, L>))]
#[kinds((uint_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs)
},
Shr::shr(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs)
},
}
}
make_impls! {
#[kinds((sint_at_most_value<'l, L>))]
#[kinds((uint_value<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shl(rhs.to_valueless()).ty();
let rhs: usize = rhs.value_to_bigint().try_into().expect("dynamic left-shift's amount is too big");
ty.from_int_wrapping(self.value_to_bigint() << rhs)
},
Shr::shr(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shr(rhs.to_valueless()).ty();
let rhs = rhs.value_to_bigint().try_into().unwrap_or(usize::MAX);
ty.from_int_wrapping(self.value_to_bigint() >> rhs)
},
}
}
make_impls! {
#[kinds((uint_value<'l, L>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shl(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() << rhs)
},
Shr::shr(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shr(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() >> rhs)
},
}
}
make_impls! {
#[kinds((sint_value<'l, L>))]
impl_shift_binary_op_trait! {
[][] (usize),
Shl::shl(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shl(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() << rhs)
},
Shr::shr(self, rhs) -> SimValueInner<_> {
let ty = self.to_valueless().shr(rhs).ty();
ty.from_int_wrapping(self.value_to_bigint() >> rhs)
},
}
}
make_impls! {
#[kinds((uint_at_most_expr<'l, L>))]
#[kinds((Valueless<UIntType<R: Size>>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Valueless<_> {
self.to_valueless().shl(rhs)
},
Shr::shr(self, rhs) -> Valueless<_> {
self.to_valueless().shr(rhs)
},
}
}
make_impls! {
#[kinds((sint_at_most_expr<'l, L>))]
#[kinds((Valueless<UIntType<R: Size>>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Valueless<_> {
self.to_valueless().shl(rhs)
},
Shr::shr(self, rhs) -> Valueless<_> {
self.to_valueless().shr(rhs)
},
}
}
make_impls! {
#[kinds((Valueless<UIntType<L: Size>>))]
#[kinds((uint_local_at_most_expr<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Valueless<_> {
self.shl(rhs.to_valueless())
},
Shr::shr(self, rhs) -> Valueless<_> {
self.shr(rhs.to_valueless())
},
}
}
make_impls! {
#[kinds((Valueless<SIntType<L: Size>>))]
#[kinds((uint_local_at_most_expr<'r, R>))]
impl_shift_binary_op_trait! {
Shl::shl(self, rhs) -> Valueless<_> {
self.shl(rhs.to_valueless())
},
Shr::shr(self, rhs) -> Valueless<_> {
self.shr(rhs.to_valueless())
},
}
}
macro_rules! impl_unary_op_trait {
(
[$($Lifetimes:tt)*][$($Bounds:tt)*] ($($Ty:tt)*),
$(#[$meta:meta])*
$Trait:ident::$f:ident($f_self:ident) -> $Out:ident<_> $body:block $(,)?
) => {
$(#[$meta])*
impl<$($Lifetimes)* $($Bounds)*> $Trait for $($Ty)* {
type Output = $Out<<<Valueless<<$($Ty)* as ValueType>::Type> as $Trait>::Output as ValueType>::Type>;
fn $f($f_self) -> Self::Output $body
}
};
(
$Lifetimes:tt $Bounds:tt $Ty:tt,
$(#[$meta:meta])*
$FirstTrait:ident::$first_f:ident($f_self:ident) -> $Out:ident<_> $body:block,
$($rest:tt)*
) => {
impl_unary_op_trait! {
$Lifetimes $Bounds $Ty,
$(#[$meta])*
$FirstTrait::$first_f($f_self) -> $Out<_> $body
}
impl_unary_op_trait! {
$Lifetimes $Bounds $Ty,
$(#[$meta])*
$($rest)*
}
};
}
make_impls! {
#[kinds((SimValue<UIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(SimValue::into_value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((&'a SimValue<UIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(SimValue::value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((Expr<UIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> Expr<_> {
NotU::new(self).to_expr()
},
}
}
make_impls! {
#[kinds((SimValue<SIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(SimValue::into_value(self)).into_sim_value()
},
StdNeg::neg(self) -> SimValue<_> {
StdNeg::neg(SimValue::into_value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((&'a SimValue<SIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(SimValue::value(self)).into_sim_value()
},
StdNeg::neg(self) -> SimValue<_> {
StdNeg::neg(SimValue::value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((Expr<SIntType<Width: Size>>))]
impl_unary_op_trait! {
Not::not(self) -> Expr<_> {
NotS::new(self).to_expr()
},
StdNeg::neg(self) -> Expr<_> {
Neg::new(Expr::as_dyn_int(self)).to_expr()
},
}
}
make_impls! {
#[kinds((SimValue<Bool>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(SimValue::into_value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((&'a SimValue<Bool>))]
impl_unary_op_trait! {
Not::not(self) -> SimValue<_> {
Not::not(*SimValue::value(self)).into_sim_value()
},
}
}
make_impls! {
#[kinds((Expr<Bool>))]
impl_unary_op_trait! {
Not::not(self) -> Expr<_> {
NotB::new(self).to_expr()
},
}
}
macro_rules! impl_get_target_none {
([$($generics:tt)*] $ty:ty) => {
impl<$($generics)*> GetTarget for $ty {
fn target(&self) -> Option<Interned<Target>> {
None
}
}
};
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct NotU<Width: Size = DynSize> {
arg: Expr<UIntType<Width>>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<Width: Size> NotU<Width> {
pub fn new(arg: Expr<UIntType<Width>>) -> Self {
Self {
arg,
literal_bits: arg
.to_literal_bits()
.map(|bits| Intern::intern_owned(bits.to_bitvec().not())),
}
}
pub fn arg(self) -> Expr<UIntType<Width>> {
self.arg
}
}
impl<Width: Size> ValueType for NotU<Width> {
type Type = UIntType<Width>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.arg.to_valueless().not().ty()
}
}
impl<Width: Size> ToExpr for NotU<Width> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::NotU(NotU {
arg: Expr::as_dyn_int(self.arg),
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<Width: Size> ToLiteralBits for NotU<Width> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([Width: Size] NotU<Width>);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct NotS<Width: Size = DynSize> {
arg: Expr<SIntType<Width>>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<Width: Size> NotS<Width> {
pub fn new(arg: Expr<SIntType<Width>>) -> Self {
Self {
arg,
literal_bits: arg
.to_literal_bits()
.map(|bits| Intern::intern_owned(bits.to_bitvec().not())),
}
}
pub fn arg(self) -> Expr<SIntType<Width>> {
self.arg
}
}
impl<Width: Size> ValueType for NotS<Width> {
type Type = UIntType<Width>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.arg.to_valueless().not().ty()
}
}
impl<Width: Size> ToExpr for NotS<Width> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::NotS(NotS {
arg: Expr::as_dyn_int(self.arg),
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<Width: Size> ToLiteralBits for NotS<Width> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([Width: Size] NotS<Width>);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct NotB {
arg: Expr<Bool>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl NotB {
pub fn new(arg: Expr<Bool>) -> Self {
Self {
arg,
literal_bits: arg
.to_literal_bits()
.map(|bits| Intern::intern_owned(bits.to_bitvec().not())),
}
}
pub fn arg(self) -> Expr<Bool> {
self.arg
}
}
impl ValueType for NotB {
type Type = Bool;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
Bool
}
}
impl ToExpr for NotB {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::NotB(NotB {
arg: self.arg,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.arg.ty(),
__flow: Flow::Source,
}
}
}
impl ToLiteralBits for NotB {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] NotB);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Neg {
arg: Expr<SInt>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl Neg {
pub fn new(arg: Expr<SInt>) -> Self {
let mut retval = Self {
arg,
literal_bits: Err(NotALiteralExpr),
};
let result_ty = retval.ty();
retval.literal_bits = arg.to_literal_bits().map(|bits| {
Intern::intern_owned(result_ty.bits_from_bigint_wrapping(&-SInt::bits_to_bigint(&bits)))
});
retval
}
pub fn arg(self) -> Expr<SInt> {
self.arg
}
}
impl ValueType for Neg {
type Type = SInt;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.arg.to_valueless().neg().ty()
}
}
impl ToExpr for Neg {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Neg(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl ToLiteralBits for Neg {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] Neg);
fn binary_op_literal_bits<ResultTy: BoolOrIntType, Lhs: BoolOrIntType, Rhs: BoolOrIntType>(
result_ty: ResultTy,
lhs: Expr<Lhs>,
rhs: Expr<Rhs>,
f: impl FnOnce(BigInt, BigInt) -> Result<BigInt, NotALiteralExpr>,
) -> Result<Interned<BitSlice>, NotALiteralExpr> {
let lhs = lhs.to_literal_bits()?;
let rhs = rhs.to_literal_bits()?;
let lhs = Lhs::bits_to_bigint(&lhs);
let rhs = Rhs::bits_to_bigint(&rhs);
let result = f(lhs, rhs)?;
Ok(Intern::intern_owned(
result_ty.bits_from_bigint_wrapping(&result),
))
}
macro_rules! binary_op_bitwise {
($name:ident, $ty:ident, bool, $Trait:ident::$method:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: Expr<$ty>) -> Self {
Self {
lhs,
rhs,
literal_bits: binary_op_literal_bits($ty, lhs, rhs, |lhs, rhs| {
Ok($Trait::$method(lhs, rhs))
}),
}
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<$ty> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
$ty
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: $ty,
__flow: Flow::Source,
}
}
}
};
($name:ident, $ty:ident, $value:ident, $Trait:ident::$method:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: Expr<$ty>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
Ok($Trait::$method(lhs, rhs))
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<$ty> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = UInt;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().$method(self.rhs.to_valueless()).ty()
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
binary_op_bitwise!(BitAndU, UIntType, UIntValue, BitAnd::bitand);
binary_op_bitwise!(BitAndS, SIntType, SIntValue, BitAnd::bitand);
binary_op_bitwise!(BitAndB, Bool, bool, BitAnd::bitand);
binary_op_bitwise!(BitOrU, UIntType, UIntValue, BitOr::bitor);
binary_op_bitwise!(BitOrS, SIntType, SIntValue, BitOr::bitor);
binary_op_bitwise!(BitOrB, Bool, bool, BitOr::bitor);
binary_op_bitwise!(BitXorU, UIntType, UIntValue, BitXor::bitxor);
binary_op_bitwise!(BitXorS, SIntType, SIntValue, BitXor::bitxor);
binary_op_bitwise!(BitXorB, Bool, bool, BitXor::bitxor);
macro_rules! binary_op_add_sub {
($name:ident, $ty:ident, $value:ident, $Trait:ident::$method:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: Expr<$ty>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
Ok($Trait::$method(lhs, rhs))
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<$ty> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
$Trait::$method(self.lhs.to_valueless(), self.rhs.to_valueless()).ty()
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
binary_op_add_sub!(AddU, UIntType, UIntValue, Add::add);
binary_op_add_sub!(AddS, SIntType, SIntValue, Add::add);
binary_op_add_sub!(SubU, UIntType, UIntValue, Sub::sub);
binary_op_add_sub!(SubS, SIntType, SIntValue, Sub::sub);
macro_rules! binary_op_mul {
($name:ident, $ty:ident, $value:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: Expr<$ty>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
Ok(Mul::mul(lhs, rhs))
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<$ty> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().mul(self.rhs.to_valueless()).ty()
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
binary_op_mul!(MulU, UIntType, UIntValue);
binary_op_mul!(MulS, SIntType, SIntValue);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct DivU<LhsWidth: Size = DynSize> {
lhs: Expr<UIntType<LhsWidth>>,
rhs: Expr<UInt>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<LhsWidth: Size> DivU<LhsWidth> {
pub fn new(lhs: Expr<UIntType<LhsWidth>>, rhs: Expr<UInt>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
lhs.checked_div(&rhs).ok_or(NotALiteralExpr)
});
retval
}
pub fn lhs(self) -> Expr<UIntType<LhsWidth>> {
self.lhs
}
pub fn rhs(self) -> Expr<UInt> {
self.rhs
}
}
impl<LhsWidth: Size> ToLiteralBits for DivU<LhsWidth> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([LhsWidth: Size] DivU<LhsWidth>);
impl<LhsWidth: Size> ValueType for DivU<LhsWidth> {
type Type = UIntType<LhsWidth>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().div(self.rhs.to_valueless()).ty()
}
}
impl<LhsWidth: Size> ToExpr for DivU<LhsWidth> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::DivU(DivU {
lhs: Expr::as_dyn_int(self.lhs),
rhs: self.rhs,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct DivS {
lhs: Expr<SInt>,
rhs: Expr<SInt>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl DivS {
pub fn new(lhs: Expr<SInt>, rhs: Expr<SInt>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
lhs.checked_div(&rhs).ok_or(NotALiteralExpr)
});
retval
}
pub fn lhs(self) -> Expr<SInt> {
self.lhs
}
pub fn rhs(self) -> Expr<SInt> {
self.rhs
}
}
impl ToLiteralBits for DivS {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] DivS);
impl ValueType for DivS {
type Type = SInt;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().div(self.rhs.to_valueless()).ty()
}
}
impl ToExpr for DivS {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::DivS(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
macro_rules! binary_op_rem {
($name:ident, $ty:ident, $value:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: Expr<$ty>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
if rhs.is_zero() {
Err(NotALiteralExpr)
} else {
Ok(lhs % rhs)
}
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<$ty> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().rem(self.rhs.to_valueless()).ty()
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
binary_op_rem!(RemU, UIntType, UIntValue);
binary_op_rem!(RemS, SIntType, SIntValue);
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct BundleLiteral<T: BundleType = Bundle> {
ty: T,
field_values: Interned<[Expr<CanonicalType>]>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<T: BundleType> BundleLiteral<T> {
#[track_caller]
pub fn new(ty: T, field_values: Interned<[Expr<CanonicalType>]>) -> Self {
let fields = ty.fields();
assert!(
Bundle::new(fields).type_properties().is_passive,
"bundle literal's type must be a passive type"
);
assert_eq!(fields.len(), field_values.len());
let mut literal_bits = Some(BitVec::new());
for (&field, &field_value) in fields.iter().zip(field_values.iter()) {
assert_eq!(
field.ty,
field_value.ty(),
"field's type doesn't match value's type: field name {:?}",
field.name
);
if let (Some(literal_bits), Ok(field_bits)) =
(&mut literal_bits, field_value.to_literal_bits())
{
literal_bits.extend_from_bitslice(&field_bits);
} else {
literal_bits = None;
}
}
Self {
ty,
field_values,
literal_bits: literal_bits
.map(Intern::intern_owned)
.ok_or(NotALiteralExpr),
}
}
pub fn field_values(self) -> Interned<[Expr<CanonicalType>]> {
self.field_values
}
}
impl<T: BundleType> ToLiteralBits for BundleLiteral<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([T: BundleType] BundleLiteral<T>);
impl<T: BundleType> ValueType for BundleLiteral<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: BundleType> ToExpr for BundleLiteral<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::BundleLiteral(BundleLiteral {
ty: Bundle::new(self.ty.fields()),
field_values: self.field_values,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty,
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct ArrayLiteral<Element: Type, Len: Size> {
element_type: Element,
element_values: Interned<[Expr<CanonicalType>]>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
_phantom: PhantomData<Len>,
}
impl<Element: Type, Len: Size> ArrayLiteral<Element, Len> {
#[track_caller]
pub fn new(element_type: Element, element_values: Interned<[Expr<CanonicalType>]>) -> Self {
let canonical_element_type = element_type.canonical();
assert!(
canonical_element_type.is_passive(),
"array literal's type must be a passive type"
);
Len::from_usize(element_values.len()); // check that len is correct
let mut literal_bits = Some(BitVec::new());
for &element_value in element_values.iter() {
assert_eq!(
canonical_element_type,
element_value.ty(),
"array's element type doesn't match element value's type",
);
if let (Some(literal_bits), Ok(element_bits)) =
(&mut literal_bits, element_value.to_literal_bits())
{
literal_bits.extend_from_bitslice(&element_bits);
} else {
literal_bits = None;
}
}
Self {
element_type,
element_values,
literal_bits: literal_bits
.map(Intern::intern_owned)
.ok_or(NotALiteralExpr),
_phantom: PhantomData,
}
}
pub fn element_type(self) -> Element {
self.element_type
}
pub fn len(self) -> usize {
self.element_values.len()
}
pub fn is_empty(self) -> bool {
self.element_values.is_empty()
}
pub fn element_values(self) -> Interned<[Expr<CanonicalType>]> {
self.element_values
}
}
impl<Element: Type, Len: Size> ToLiteralBits for ArrayLiteral<Element, Len> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([Element: Type, Len: Size] ArrayLiteral<Element, Len>);
impl<Element: Type, Len: Size> ValueType for ArrayLiteral<Element, Len> {
type Type = ArrayType<Element, Len>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
ArrayType::new(
self.element_type,
Len::from_usize(self.element_values.len()),
)
}
}
impl<Element: Type, Len: Size> ToExpr for ArrayLiteral<Element, Len> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ArrayLiteral(ArrayLiteral {
element_type: self.element_type.canonical(),
element_values: self.element_values,
literal_bits: self.literal_bits,
_phantom: PhantomData,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<T: ValueType<Type: StaticType>, const N: usize> ValueType for [T; N]
where
ConstUsize<N>: KnownSize,
{
type Type = Array<T::Type, N>;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
StaticType::TYPE
}
}
impl<T: ToExpr<Type: StaticType>, const N: usize> ToExpr for [T; N]
where
ConstUsize<N>: KnownSize,
{
fn to_expr(&self) -> Expr<Self::Type> {
ArrayLiteral::new(
T::Type::TYPE,
self.iter().map(|v| Expr::canonical(v.to_expr())).collect(),
)
.to_expr()
}
}
impl<T: ValueType<Type: StaticType>> ValueType for [T] {
type Type = Array<T::Type>;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
ArrayType::new_dyn(StaticType::TYPE, self.len())
}
}
impl<T: ToExpr<Type: StaticType>> ToExpr for [T] {
fn to_expr(&self) -> Expr<Self::Type> {
ArrayLiteral::new(
T::Type::TYPE,
self.iter().map(|v| Expr::canonical(v.to_expr())).collect(),
)
.to_expr()
}
}
impl<T: ValueType<Type: StaticType>> ValueType for Vec<T> {
type Type = Array<T::Type>;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
<[T]>::ty(self)
}
}
impl<T: ToExpr<Type: StaticType>> ToExpr for Vec<T> {
fn to_expr(&self) -> Expr<Self::Type> {
<[T]>::to_expr(self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct EnumLiteral<T: EnumType = Enum> {
ty: T,
variants: Interned<[EnumVariant]>,
variant_index: usize,
variant_value: Option<Expr<CanonicalType>>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<T: EnumType> EnumLiteral<T> {
#[track_caller]
pub fn new_by_index(
ty: T,
variant_index: usize,
variant_value: Option<Expr<CanonicalType>>,
) -> Self {
let variants = ty.variants();
let canonical_ty = Enum::new(variants);
assert!(variant_index < variants.len());
assert_eq!(
variants[variant_index].ty,
variant_value.map(|v| v.ty()),
"variant's type doesn't match value's type: variant name {:?}",
variants[variant_index].name
);
let literal_bits = if let Ok(variant_value) = variant_value
.map(|variant_value| variant_value.to_literal_bits())
.transpose()
{
let mut literal_bits = BitVec::with_capacity(canonical_ty.type_properties().bit_width);
literal_bits.extend_from_bitslice(
&[variant_index].view_bits::<Lsb0>()[..canonical_ty.discriminant_bit_width()],
);
if let Some(variant_value) = variant_value {
literal_bits.extend_from_bitslice(&variant_value);
}
literal_bits.resize(canonical_ty.type_properties().bit_width, false);
Ok(Intern::intern_owned(literal_bits))
} else {
Err(NotALiteralExpr)
};
Self {
ty,
variants,
variant_index,
variant_value,
literal_bits,
}
}
#[track_caller]
pub fn new_by_name(
ty: T,
variant_name: Interned<str>,
variant_value: Option<Expr<CanonicalType>>,
) -> Self {
let enum_ty = Enum::new(ty.variants());
let Some(variant_index) = enum_ty.name_indexes().get(&variant_name) else {
panic!("unknown variant {variant_name:?}: in {ty:?}");
};
Self::new_by_index(ty, *variant_index, variant_value)
}
pub fn variant_index(self) -> usize {
self.variant_index
}
pub fn variant_name(self) -> Interned<str> {
self.variants[self.variant_index].name
}
pub fn variant_value(self) -> Option<Expr<CanonicalType>> {
self.variant_value
}
}
impl<T: EnumType> ToLiteralBits for EnumLiteral<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([T: EnumType] EnumLiteral<T>);
impl<T: EnumType> ValueType for EnumLiteral<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: EnumType> ToExpr for EnumLiteral<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::EnumLiteral(EnumLiteral {
ty: Enum::new(self.variants),
variants: self.variants,
variant_index: self.variant_index,
variant_value: self.variant_value,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty,
__flow: Flow::Source,
}
}
}
macro_rules! impl_dyn_shl {
($name:ident, $ty:ident, $value:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: Expr<UInt>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
#[track_caller]
pub fn new(lhs: Expr<$ty>, rhs: Expr<UInt>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
Ok(lhs << rhs.to_usize().ok_or(NotALiteralExpr)?)
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> Expr<UInt> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
#[track_caller]
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().shl(self.rhs.to_valueless()).ty()
}
}
impl ToExpr for $name {
#[track_caller]
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
impl_dyn_shl!(DynShlU, UIntType, UIntValue);
impl_dyn_shl!(DynShlS, SIntType, SIntValue);
macro_rules! impl_dyn_shr {
($name:ident, $ty:ident, $value:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name<LhsWidth: Size = DynSize> {
lhs: Expr<$ty<LhsWidth>>,
rhs: Expr<UInt>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<LhsWidth: Size> $name<LhsWidth> {
#[track_caller]
pub fn new(lhs: Expr<$ty<LhsWidth>>, rhs: Expr<UInt>) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = binary_op_literal_bits(retval.ty(), lhs, rhs, |lhs, rhs| {
Ok(lhs >> rhs.to_usize().ok_or(NotALiteralExpr)?)
});
retval
}
pub fn lhs(self) -> Expr<$ty<LhsWidth>> {
self.lhs
}
pub fn rhs(self) -> Expr<UInt> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl<LhsWidth: Size> ValueType for $name<LhsWidth> {
type Type = $ty<LhsWidth>;
type ValueCategory = ValueCategoryExpr;
#[track_caller]
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().shr(self.rhs.to_valueless()).ty()
}
}
impl<LhsWidth: Size> ToExpr for $name<LhsWidth> {
#[track_caller]
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name($name {
lhs: Expr::as_dyn_int(self.lhs),
rhs: self.rhs,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
impl_dyn_shr!(DynShrU, UIntType, UIntValue);
impl_dyn_shr!(DynShrS, SIntType, SIntValue);
macro_rules! binary_op_fixed_shift {
($name:ident, $ty:ident, $Trait:ident::$method:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$ty>,
rhs: usize,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$ty>, rhs: usize) -> Self {
let mut retval = Self {
lhs,
rhs,
literal_bits: Err(NotALiteralExpr),
};
retval.literal_bits = lhs.to_literal_bits().map(|bits| {
Intern::intern_owned(retval.ty().bits_from_bigint_wrapping(&$Trait::$method(
$ty::bits_to_bigint(&bits),
rhs,
)))
});
retval
}
pub fn lhs(self) -> Expr<$ty> {
self.lhs
}
pub fn rhs(self) -> usize {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $ty;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.lhs.to_valueless().$method(self.rhs).ty()
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
};
}
binary_op_fixed_shift!(FixedShlU, UInt, Shl::shl);
binary_op_fixed_shift!(FixedShlS, SInt, Shl::shl);
binary_op_fixed_shift!(FixedShrU, UInt, Shr::shr);
binary_op_fixed_shift!(FixedShrS, SInt, Shr::shr);
macro_rules! impl_compare_op {
(
$(#[width($LhsWidth:ident, $RhsWidth:ident)])?
#[dyn_type($DynTy:ident)]
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
#[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)]
#[type($Lhs:ty, $Rhs:ty)]
#[trait($Trait:ident)]
$(
struct $name:ident;
fn $value_method:ident();
fn $expr_method:ident();
$CmpTrait:ident::$cmp_method:ident();
)*
) => {
$(#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
lhs: Expr<$DynTy>,
rhs: Expr<$DynTy>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(lhs: Expr<$DynTy>, rhs: Expr<$DynTy>) -> Self {
Self {
lhs,
rhs,
literal_bits: binary_op_literal_bits(Bool, lhs, rhs, |lhs, rhs| {
Ok($CmpTrait::$cmp_method(&lhs, &rhs).into())
}),
}
}
pub fn lhs(self) -> Expr<$DynTy> {
self.lhs
}
pub fn rhs(self) -> Expr<$DynTy> {
self.rhs
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = Bool;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
Bool
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: Bool,
__flow: Flow::Source,
}
}
})*
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
$(fn $value_method(
_lhs: Self,
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
_rhs: $Rhs,
$rhs_compare_value: Cow<'_, <$Rhs as Type>::SimValue>,
) -> bool {
$CmpTrait::$cmp_method($lhs_compare_value_expr, $rhs_compare_value_expr)
})*
$(fn $expr_method($lhs: Expr<Self>, $rhs: Expr<$Rhs>) -> Expr<Bool> {
$name::new($dyn_lhs, $dyn_rhs).to_expr()
})*
}
};
}
impl_compare_op! {
#[dyn_type(Bool)]
#[to_dyn_type(lhs => lhs, rhs => rhs)]
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
#[type(Bool, Bool)]
#[trait(HdlPartialEqImpl)]
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
}
impl_compare_op! {
#[dyn_type(Bool)]
#[to_dyn_type(lhs => lhs, rhs => rhs)]
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
#[type(Bool, Bool)]
#[trait(HdlPartialOrdImpl)]
struct CmpLtB; fn cmp_value_lt(); fn cmp_expr_lt(); PartialOrd::lt();
struct CmpLeB; fn cmp_value_le(); fn cmp_expr_le(); PartialOrd::le();
struct CmpGtB; fn cmp_value_gt(); fn cmp_expr_gt(); PartialOrd::gt();
struct CmpGeB; fn cmp_value_ge(); fn cmp_expr_ge(); PartialOrd::ge();
}
impl_compare_op! {
#[width(LhsWidth, RhsWidth)]
#[dyn_type(UInt)]
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
#[trait(HdlPartialEqImpl)]
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
}
impl_compare_op! {
#[width(LhsWidth, RhsWidth)]
#[dyn_type(UInt)]
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
#[trait(HdlPartialOrdImpl)]
struct CmpLtU; fn cmp_value_lt(); fn cmp_expr_lt(); PartialOrd::lt();
struct CmpLeU; fn cmp_value_le(); fn cmp_expr_le(); PartialOrd::le();
struct CmpGtU; fn cmp_value_gt(); fn cmp_expr_gt(); PartialOrd::gt();
struct CmpGeU; fn cmp_value_ge(); fn cmp_expr_ge(); PartialOrd::ge();
}
impl_compare_op! {
#[width(LhsWidth, RhsWidth)]
#[dyn_type(SInt)]
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
#[trait(HdlPartialEqImpl)]
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
}
impl_compare_op! {
#[width(LhsWidth, RhsWidth)]
#[dyn_type(SInt)]
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
#[trait(HdlPartialOrdImpl)]
struct CmpLtS; fn cmp_value_lt(); fn cmp_expr_lt(); PartialOrd::lt();
struct CmpLeS; fn cmp_value_le(); fn cmp_expr_le(); PartialOrd::le();
struct CmpGtS; fn cmp_value_gt(); fn cmp_expr_gt(); PartialOrd::gt();
struct CmpGeS; fn cmp_value_ge(); fn cmp_expr_ge(); PartialOrd::ge();
}
macro_rules! impl_compare_forwards_to_bool {
($ty:ident) => {
impl HdlPartialEqImpl<Self> for $ty {
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
_rhs: Self,
rhs_value: Cow<'_, Self::SimValue>,
) -> bool {
*lhs_value == *rhs_value
}
#[track_caller]
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_eq(rhs.cast_to(Bool))
}
#[track_caller]
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_ne(rhs.cast_to(Bool))
}
}
impl HdlPartialOrdImpl<Self> for $ty {
#[track_caller]
fn cmp_value_lt(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
_rhs: Self,
rhs_value: Cow<'_, <Self as Type>::SimValue>,
) -> bool {
PartialOrd::lt(&*lhs_value, &*rhs_value)
}
#[track_caller]
fn cmp_value_le(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
_rhs: Self,
rhs_value: Cow<'_, <Self as Type>::SimValue>,
) -> bool {
PartialOrd::le(&*lhs_value, &*rhs_value)
}
#[track_caller]
fn cmp_value_gt(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
_rhs: Self,
rhs_value: Cow<'_, <Self as Type>::SimValue>,
) -> bool {
PartialOrd::gt(&*lhs_value, &*rhs_value)
}
#[track_caller]
fn cmp_value_ge(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
_rhs: Self,
rhs_value: Cow<'_, <Self as Type>::SimValue>,
) -> bool {
PartialOrd::ge(&*lhs_value, &*rhs_value)
}
#[track_caller]
fn cmp_expr_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_lt(rhs.cast_to(Bool))
}
#[track_caller]
fn cmp_expr_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_le(rhs.cast_to(Bool))
}
#[track_caller]
fn cmp_expr_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_gt(rhs.cast_to(Bool))
}
#[track_caller]
fn cmp_expr_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to(Bool).cmp_ge(rhs.cast_to(Bool))
}
}
};
}
impl_compare_forwards_to_bool!(Clock);
impl_compare_forwards_to_bool!(Reset);
impl_compare_forwards_to_bool!(SyncReset);
impl_compare_forwards_to_bool!(AsyncReset);
impl CastToImpl<Bool> for Bool {
type ValueOutput = bool;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
_to_type: Bool,
) -> Self::ValueOutput {
*value
}
fn cast_sim_value_to(value: Cow<'_, SimValue<Self>>, _to_type: Bool) -> SimValue<Bool> {
value.into_owned()
}
fn cast_expr_to(value: Expr<Self>, _to_type: Bool) -> Expr<Bool> {
value
}
fn cast_valueless_to(value: Valueless<Self>, _to_type: Bool) -> Valueless<Bool> {
value
}
}
macro_rules! impl_cast_int_op {
($name:ident, $from:ident, $to:ident, $to_value:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name<ToWidth: Size = DynSize> {
arg: Expr<$from>,
ty: $to<ToWidth>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<ToWidth: Size> $name<ToWidth> {
pub fn new(arg: Expr<$from>, ty: $to<ToWidth>) -> Self {
Self {
arg,
ty,
literal_bits: arg.to_literal_bits().map(|bits| {
Intern::intern_owned(
ty.bits_from_bigint_wrapping(&$from::bits_to_bigint(&bits)),
)
}),
}
}
pub fn arg(self) -> Expr<$from> {
self.arg
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([ToWidth: Size] $name<ToWidth>);
impl<ToWidth: Size> ValueType for $name<ToWidth> {
type Type = $to<ToWidth>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<ToWidth: Size> ToExpr for $name<ToWidth> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name($name {
arg: self.arg,
ty: self.ty.as_dyn_int(),
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty,
__flow: Flow::Source,
}
}
}
impl<FromWidth: Size, ToWidth: Size> CastToImpl<$to<ToWidth>> for $from<FromWidth> {
type ValueOutput = $to_value<ToWidth>;
fn cast_value_to(_this: Self, value: Cow<'_, Self::SimValue>, to_type: $to<ToWidth>) -> Self::ValueOutput {
to_type.from_int_wrapping(value.to_bigint())
}
fn cast_expr_to(value: Expr<Self>, to_type: $to<ToWidth>) -> Expr<$to<ToWidth>> {
$name::new(Expr::as_dyn_int(value), to_type).to_expr()
}
}
};
}
impl_cast_int_op!(CastUIntToUInt, UIntType, UIntType, UIntValue);
impl_cast_int_op!(CastUIntToSInt, UIntType, SIntType, SIntValue);
impl_cast_int_op!(CastSIntToUInt, SIntType, UIntType, UIntValue);
impl_cast_int_op!(CastSIntToSInt, SIntType, SIntType, SIntValue);
macro_rules! impl_cast_bit_op {
($name:ident, $from:ty, $(#[dyn] $from_dyn:ty,)? $to:ty, #[to_value = $to_value_expr:expr] $to_value:ty, #[trait] $Trait:ident::$trait_fn:ident $(,)?) => {
impl_cast_bit_op!($name, $from, $(#[dyn] $from_dyn,)? $to, #[to_value = $to_value_expr] $to_value);
impl $Trait for Expr<$from> {
type Output = Expr<$to>;
fn $trait_fn(&self) -> Self::Output {
self.cast_to_static()
}
}
$(impl $Trait for Expr<$from_dyn> {
type Output = Expr<$to>;
fn $trait_fn(&self) -> Self::Output {
self.cast_to_static()
}
})?
};
($name:ident, $from:ty, $to:ty, #[to_value = $to_value_expr:expr] $to_value:ty, #[dyn] $to_dyn:ty $(,)?) => {
impl_cast_bit_op!($name, $from, $to, #[to_value = $to_value_expr] $to_value);
impl CastToImpl<$to_dyn> for $from {
type ValueOutput = <$to_dyn as BoolOrIntType>::Value;
fn cast_value_to(this: Self, value: Cow<'_, Self::SimValue>, to_type: $to_dyn) -> Self::ValueOutput {
<Self as CastToImpl<$to>>::cast_value_to(this, value, StaticType::TYPE).cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: $to_dyn) -> Expr<$to_dyn> {
assert!(to_type.width() == 1);
Expr::as_dyn_int(
$name::new(value).to_expr(),
)
}
}
};
($name:ident, $from:ty, $(#[dyn] $from_dyn:ty,)? $to:ty, #[to_value = $to_value_expr:expr] $to_value:ty $(,)?) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
arg: Expr<$from>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(arg: Expr<$from>) -> Self {
Self {
arg,
literal_bits: arg.to_literal_bits(),
}
}
pub fn arg(self) -> Expr<$from> {
self.arg
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = $to;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
Self::Type::TYPE
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: <$to>::TYPE,
__flow: Flow::Source,
}
}
}
impl CastToImpl<$to> for $from {
type ValueOutput = $to_value;
fn cast_value_to(this: Self, value: Cow<'_, Self::SimValue>, to_type: $to) -> Self::ValueOutput {
($to_value_expr)(this, value, to_type)
}
fn cast_expr_to(value: Expr<Self>, _to_type: $to) -> Expr<$to> {
$name::new(value).to_expr()
}
}
$(impl CastToImpl<$to> for $from_dyn {
type ValueOutput = $to_value;
fn cast_value_to(this: Self, value: Cow<'_, Self::SimValue>, to_type: $to) -> Self::ValueOutput {
<$from_dyn as CastToImpl<$from>>::cast_value_to(this, value, StaticType::TYPE).cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, _to_type: $to) -> Expr<$to> {
$name::new(Expr::<$from>::from_dyn_int(value)).to_expr()
}
})?
};
}
impl_cast_bit_op!(CastBoolToUInt, Bool, UInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] UIntValue<ConstUsize<1>>, #[dyn] UInt);
impl_cast_bit_op!(CastBoolToSInt, Bool, SInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] SIntValue<ConstUsize<1>>, #[dyn] SInt);
impl_cast_bit_op!(CastUIntToBool, UInt<1>, #[dyn] UInt, Bool, #[to_value = |_, v: Cow<'_, UIntValue<_>>, _| v.bits()[0]] bool);
impl_cast_bit_op!(CastSIntToBool, SInt<1>, #[dyn] SInt, Bool, #[to_value = |_, v: Cow<'_, SIntValue<_>>, _| v.bits()[0]] bool);
impl_cast_bit_op!(CastBoolToSyncReset, Bool, SyncReset, #[to_value = |_, v: Cow<'_, bool>, _| v.to_sync_reset()] SimValue<SyncReset>, #[trait] ToSyncReset::to_sync_reset);
impl_cast_bit_op!(CastUIntToSyncReset, UInt<1>, #[dyn] UInt, SyncReset, #[to_value = |_, v: Cow<'_, UIntValue<_>>, _| v.bits()[0].to_sync_reset()] SimValue<SyncReset>, #[trait] ToSyncReset::to_sync_reset);
impl_cast_bit_op!(CastSIntToSyncReset, SInt<1>, #[dyn] SInt, SyncReset, #[to_value = |_, v: Cow<'_, SIntValue<_>>, _| v.bits()[0].to_sync_reset()] SimValue<SyncReset>, #[trait] ToSyncReset::to_sync_reset);
impl_cast_bit_op!(CastBoolToAsyncReset, Bool, AsyncReset, #[to_value = |_, v: Cow<'_, bool>, _| v.to_async_reset()] SimValue<AsyncReset>, #[trait] ToAsyncReset::to_async_reset);
impl_cast_bit_op!(CastUIntToAsyncReset, UInt<1>, #[dyn] UInt, AsyncReset, #[to_value = |_, v: Cow<'_, UIntValue<_>>, _| v.bits()[0].to_async_reset()] SimValue<AsyncReset>, #[trait] ToAsyncReset::to_async_reset);
impl_cast_bit_op!(CastSIntToAsyncReset, SInt<1>, #[dyn] SInt, AsyncReset, #[to_value = |_, v: Cow<'_, SIntValue<_>>, _| v.bits()[0].to_async_reset()] SimValue<AsyncReset>, #[trait] ToAsyncReset::to_async_reset);
impl_cast_bit_op!(
CastSyncResetToBool,
SyncReset,
Bool,
#[to_value = |_, v: Cow<'_, bool>, _| *v]
bool
);
impl_cast_bit_op!(CastSyncResetToUInt, SyncReset, UInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] UIntValue<ConstUsize<1>>, #[dyn] UInt);
impl_cast_bit_op!(CastSyncResetToSInt, SyncReset, SInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] SIntValue<ConstUsize<1>>, #[dyn] SInt);
impl_cast_bit_op!(CastSyncResetToReset, SyncReset, Reset, #[to_value = |_, v: Cow<'_, bool>, t| SimValue::from_value(t, *v)] SimValue<Reset>);
impl_cast_bit_op!(
CastAsyncResetToBool,
AsyncReset,
Bool,
#[to_value = |_, v: Cow<'_, bool>, _| *v]
bool
);
impl_cast_bit_op!(CastAsyncResetToUInt, AsyncReset, UInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] UIntValue<ConstUsize<1>>, #[dyn] UInt);
impl_cast_bit_op!(CastAsyncResetToSInt, AsyncReset, SInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] SIntValue<ConstUsize<1>>, #[dyn] SInt);
impl_cast_bit_op!(CastAsyncResetToReset, AsyncReset, Reset, #[to_value = |_, v: Cow<'_, bool>, t| SimValue::from_value(t, *v)] SimValue<Reset>);
impl_cast_bit_op!(
CastResetToBool,
Reset,
Bool,
#[to_value = |_, v: Cow<'_, bool>, _| *v]
bool
);
impl_cast_bit_op!(CastResetToUInt, Reset, UInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] UIntValue<ConstUsize<1>>, #[dyn] UInt);
impl_cast_bit_op!(CastResetToSInt, Reset, SInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] SIntValue<ConstUsize<1>>, #[dyn] SInt);
impl_cast_bit_op!(CastBoolToClock, Bool, Clock, #[to_value = |_, v: Cow<'_, bool>, _| v.to_clock()] SimValue<Clock>, #[trait] ToClock::to_clock);
impl_cast_bit_op!(CastUIntToClock, UInt<1>, #[dyn] UInt, Clock, #[to_value = |_, v: Cow<'_, UIntValue<_>>, _| v.bits()[0].to_clock()] SimValue<Clock>, #[trait] ToClock::to_clock);
impl_cast_bit_op!(CastSIntToClock, SInt<1>, #[dyn] SInt, Clock, #[to_value = |_, v: Cow<'_, SIntValue<_>>, _| v.bits()[0].to_clock()] SimValue<Clock>, #[trait] ToClock::to_clock);
impl_cast_bit_op!(
CastClockToBool,
Clock,
Bool,
#[to_value = |_, v: Cow<'_, bool>, _| *v]
bool
);
impl_cast_bit_op!(CastClockToUInt, Clock, UInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] UIntValue<ConstUsize<1>>, #[dyn] UInt);
impl_cast_bit_op!(CastClockToSInt, Clock, SInt<1>, #[to_value = |_, v: Cow<'_, bool>, _| (*v).into()] SIntValue<ConstUsize<1>>, #[dyn] SInt);
impl<T: ResetType> ToReset for Expr<T> {
type Output = Expr<Reset>;
fn to_reset(&self) -> Self::Output {
struct Dispatch;
impl ResetTypeDispatch for Dispatch {
type Input<T: ResetType> = Expr<T>;
type Output<T: ResetType> = Expr<Reset>;
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
input
}
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
input.cast_to_static()
}
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
input.cast_to_static()
}
}
T::dispatch(*self, Dispatch)
}
}
impl ToReset for SimValue<SyncReset> {
type Output = Expr<Reset>;
fn to_reset(&self) -> Self::Output {
(*self).to_expr().to_sync_reset().to_reset()
}
}
impl ToReset for SimValue<AsyncReset> {
type Output = Expr<Reset>;
fn to_reset(&self) -> Self::Output {
(*self).to_expr().to_async_reset().to_reset()
}
}
impl CastToImpl<AsyncReset> for AsyncReset {
type ValueOutput = SimValue<AsyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
_to_type: AsyncReset,
) -> Self::ValueOutput {
value.to_async_reset()
}
fn cast_expr_to(value: Expr<Self>, _to_type: AsyncReset) -> Expr<AsyncReset> {
value
}
}
impl CastToImpl<SyncReset> for AsyncReset {
type ValueOutput = SimValue<SyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
_to_type: SyncReset,
) -> Self::ValueOutput {
value.to_sync_reset()
}
fn cast_expr_to(value: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<Clock> for AsyncReset {
type ValueOutput = SimValue<Clock>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: Clock,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: Clock) -> Expr<Clock> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<AsyncReset> for SyncReset {
type ValueOutput = SimValue<AsyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: AsyncReset,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<SyncReset> for SyncReset {
type ValueOutput = SimValue<SyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
_to_type: SyncReset,
) -> Self::ValueOutput {
value.to_sync_reset()
}
fn cast_expr_to(value: Expr<Self>, _to_type: SyncReset) -> Expr<SyncReset> {
value
}
}
impl CastToImpl<Clock> for SyncReset {
type ValueOutput = SimValue<Clock>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: Clock,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: Clock) -> Expr<Clock> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<AsyncReset> for Reset {
type ValueOutput = SimValue<AsyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: AsyncReset,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<SyncReset> for Reset {
type ValueOutput = SimValue<SyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: SyncReset,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<Reset> for Reset {
type ValueOutput = SimValue<Reset>;
#[track_caller]
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: Reset,
) -> Self::ValueOutput {
SimValue::from_value(to_type, *value)
}
#[track_caller]
fn cast_expr_to(value: Expr<Self>, _to_type: Reset) -> Expr<Reset> {
value
}
}
impl CastToImpl<Clock> for Reset {
type ValueOutput = SimValue<Clock>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: Clock,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: Clock) -> Expr<Clock> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<AsyncReset> for Clock {
type ValueOutput = SimValue<AsyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: AsyncReset,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: AsyncReset) -> Expr<AsyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<SyncReset> for Clock {
type ValueOutput = SimValue<SyncReset>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
to_type: SyncReset,
) -> Self::ValueOutput {
value.cast_to(to_type)
}
fn cast_expr_to(value: Expr<Self>, to_type: SyncReset) -> Expr<SyncReset> {
value.cast_to(Bool).cast_to(to_type)
}
}
impl CastToImpl<Clock> for Clock {
type ValueOutput = SimValue<Clock>;
fn cast_value_to(
_this: Self,
value: Cow<'_, Self::SimValue>,
_to_type: Clock,
) -> Self::ValueOutput {
value.to_clock()
}
fn cast_expr_to(value: Expr<Self>, _to_type: Clock) -> Expr<Clock> {
value
}
}
impl<T: ?Sized + PhantomConstValue> CastToImpl<()> for PhantomConst<T> {
type ValueOutput = ();
fn cast_value_to(
_this: Self,
_value: Cow<'_, Self::SimValue>,
_to_type: (),
) -> Self::ValueOutput {
()
}
fn cast_expr_to(value: Expr<Self>, to_type: ()) -> Expr<()> {
value.cast_to_bits().cast_bits_to(to_type)
}
}
impl<T: ?Sized + PhantomConstValue> CastToImpl<PhantomConst<T>> for () {
type ValueOutput = PhantomConst<T>;
fn cast_value_to(
_this: Self,
_value: Cow<'_, Self::SimValue>,
to_type: PhantomConst<T>,
) -> Self::ValueOutput {
to_type
}
fn cast_expr_to(value: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
value.cast_to_bits().cast_bits_to(to_type)
}
}
impl<T: ?Sized + PhantomConstValue, U: ?Sized + PhantomConstValue> CastToImpl<PhantomConst<T>>
for PhantomConst<U>
{
type ValueOutput = PhantomConst<T>;
fn cast_value_to(
_this: Self,
_value: Cow<'_, Self::SimValue>,
to_type: PhantomConst<T>,
) -> Self::ValueOutput {
to_type
}
fn cast_expr_to(value: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
value.cast_to_bits().cast_bits_to(to_type)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct FieldAccess<FieldType: Type = CanonicalType> {
base: Expr<Bundle>,
field_index: usize,
field: BundleField,
field_type: FieldType,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<FieldType: Type + fmt::Debug> fmt::Debug for FieldAccess<FieldType> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.base.fmt(f)?;
f.write_str(".")?;
f.write_str(&self.field_name())
}
}
impl<FieldType: Type> FieldAccess<FieldType> {
#[track_caller]
pub fn new_by_index(base: Expr<Bundle>, field_index: usize) -> Self {
let field = base.ty().fields()[field_index];
let field_type = FieldType::from_canonical(field.ty);
let literal_bits = base.to_literal_bits().map(|bits| {
bits[base.ty().field_offsets()[field_index].bit_width..][..field.ty.bit_width()]
.intern()
});
let target = base.target().map(|base| {
Intern::intern_sized(base.join(TargetPathElement::intern_sized(
TargetPathBundleField { name: field.name }.into(),
)))
});
Self {
base,
field_index,
field,
field_type,
literal_bits,
target,
}
}
#[track_caller]
pub fn new_by_name(base: Expr<Bundle>, name: Interned<str>) -> Self {
let base_ty = base.ty();
let Some(field_index) = base_ty.name_indexes().get(&name) else {
panic!("unknown field {name:?}: in {base_ty:?}");
};
Self::new_by_index(base, *field_index)
}
pub fn base(self) -> Expr<Bundle> {
self.base
}
pub fn field_index(self) -> usize {
self.field_index
}
pub fn field_name(self) -> Interned<str> {
self.field.name
}
pub fn field(self) -> BundleField {
self.field
}
pub fn field_type(self) -> FieldType {
self.field_type
}
}
impl<FieldType: Type> GetTarget for FieldAccess<FieldType> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<FieldType: Type> ToLiteralBits for FieldAccess<FieldType> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<FieldType: Type> ValueType for FieldAccess<FieldType> {
type Type = FieldType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.field_type
}
}
impl<FieldType: Type> ToExpr for FieldAccess<FieldType> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::FieldAccess(FieldAccess {
base: self.base,
field_index: self.field_index,
field: self.field,
field_type: self.field_type.canonical(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.field_type,
__flow: Expr::flow(self.base).flip_if(self.field.flipped),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct VariantAccess<VariantType: Type = CanonicalType> {
base: Expr<Enum>,
variant_index: usize,
variant: EnumVariant,
variant_type: Option<VariantType>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<VariantType: Type> VariantAccess<VariantType> {
#[track_caller]
pub fn new_by_index(base: Expr<Enum>, variant_index: usize) -> Self {
let variant = base.ty().variants()[variant_index];
let variant_type = variant.ty.map(VariantType::from_canonical);
let literal_bits = base.to_literal_bits().and_then(|bits| {
let discriminant_bit_width = base.ty().discriminant_bit_width();
if bits[..discriminant_bit_width]
!= [variant_index].view_bits::<Lsb0>()[..discriminant_bit_width]
{
// wrong variant
return Err(NotALiteralExpr);
}
Ok(bits[discriminant_bit_width..]
[..variant.ty.map(CanonicalType::bit_width).unwrap_or(0)]
.intern())
});
Self {
base,
variant_index,
variant,
variant_type,
literal_bits,
}
}
#[track_caller]
pub fn new_by_name(base: Expr<Enum>, name: Interned<str>) -> Self {
let base_ty = base.ty();
let Some(variant_index) = base_ty.name_indexes().get(&name) else {
panic!("unknown variant {name:?}: in {base_ty:?}");
};
Self::new_by_index(base, *variant_index)
}
pub fn base(self) -> Expr<Enum> {
self.base
}
pub fn variant_index(self) -> usize {
self.variant_index
}
pub fn variant_name(self) -> Interned<str> {
self.variant.name
}
pub fn variant(self) -> EnumVariant {
self.variant
}
pub fn variant_type(self) -> Option<VariantType> {
self.variant_type
}
}
impl<VariantType: Type> ToLiteralBits for VariantAccess<VariantType> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([VariantType: Type] VariantAccess<VariantType>);
impl<VariantType: Type> ValueType for VariantAccess<VariantType> {
type Type = VariantType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.variant_type
.unwrap_or_else(|| VariantType::from_canonical(().canonical()))
}
}
impl<VariantType: Type> ToExpr for VariantAccess<VariantType> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::VariantAccess(VariantAccess {
base: self.base,
variant_index: self.variant_index,
variant: self.variant,
variant_type: self.variant.ty,
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct ArrayIndex<ElementType: Type = CanonicalType> {
base: Expr<Array>,
element_index: usize,
element_type: ElementType,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<ElementType: Type> ArrayIndex<ElementType> {
#[track_caller]
pub fn new(base: Expr<Array>, element_index: usize) -> Self {
let base_ty = base.ty();
assert!(element_index < base_ty.len());
let element_type = ElementType::from_canonical(base_ty.element());
let literal_bits = base.to_literal_bits().map(|bits| {
let element_bit_width = base_ty.element().bit_width();
bits[element_bit_width * element_index..][..element_bit_width].intern()
});
let target = base.target().map(|base| {
Intern::intern_sized(
base.join(
TargetPathElement::ArrayElement(TargetPathArrayElement {
index: element_index,
})
.intern(),
),
)
});
Self {
base,
element_index,
element_type,
literal_bits,
target,
}
}
pub fn base(self) -> Expr<Array> {
self.base
}
pub fn element_index(self) -> usize {
self.element_index
}
pub fn element_type(self) -> ElementType {
self.element_type
}
}
impl<ElementType: Type> ToLiteralBits for ArrayIndex<ElementType> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<ElementType: Type> GetTarget for ArrayIndex<ElementType> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<ElementType: Type> ValueType for ArrayIndex<ElementType> {
type Type = ElementType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.element_type
}
}
impl<ElementType: Type> ToExpr for ArrayIndex<ElementType> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ArrayIndex(ArrayIndex {
base: self.base,
element_index: self.element_index,
element_type: self.base.ty().element(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.element_type,
__flow: Expr::flow(self.base),
}
}
}
impl<ElementType: Type, Len: Size> ExprIndex<usize> for ArrayType<ElementType, Len> {
type Output = ElementType;
#[track_caller]
fn expr_index(this: &Expr<Self>, index: usize) -> &Expr<Self::Output> {
Interned::into_inner(
ArrayIndex::<ElementType>::new(Expr::as_dyn_array(*this), index)
.to_expr()
.intern_sized(),
)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct DynArrayIndex<ElementType: Type = CanonicalType> {
base: Expr<Array>,
element_index: Expr<UInt>,
element_type: ElementType,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<ElementType: Type> DynArrayIndex<ElementType> {
#[track_caller]
pub fn new(base: Expr<Array>, element_index: Expr<UInt>) -> Self {
let base_ty = base.ty();
let element_type = ElementType::from_canonical(base_ty.element());
let literal_bits = base
.to_literal_bits()
.ok()
.zip(element_index.to_literal_bits().ok())
.and_then(|(bits, index)| {
let index = UInt::bits_to_bigint(&index).to_usize()?;
if index >= base_ty.len() {
return None;
}
let element_bit_width = base_ty.element().bit_width();
Some(bits[element_bit_width * index..][..element_bit_width].intern())
})
.ok_or(NotALiteralExpr);
let target =
base.target().map(|base| {
Intern::intern_sized(base.join(
TargetPathElement::DynArrayElement(TargetPathDynArrayElement {}).intern(),
))
});
Self {
base,
element_index,
element_type,
literal_bits,
target,
}
}
pub fn base(self) -> Expr<Array> {
self.base
}
pub fn element_index(self) -> Expr<UInt> {
self.element_index
}
pub fn element_type(self) -> ElementType {
self.element_type
}
}
impl<ElementType: Type> ToLiteralBits for DynArrayIndex<ElementType> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<ElementType: Type> GetTarget for DynArrayIndex<ElementType> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<ElementType: Type> ValueType for DynArrayIndex<ElementType> {
type Type = ElementType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.element_type
}
}
impl<ElementType: Type> ToExpr for DynArrayIndex<ElementType> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::DynArrayIndex(DynArrayIndex {
base: self.base,
element_index: self.element_index,
element_type: self.base.ty().element(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.element_type,
__flow: Expr::flow(self.base),
}
}
}
impl<ElementType: Type, Len: Size, Width: Size> ExprIndex<Expr<UIntType<Width>>>
for ArrayType<ElementType, Len>
{
type Output = ElementType;
fn expr_index(this: &Expr<Self>, index: Expr<UIntType<Width>>) -> &Expr<Self::Output> {
Interned::into_inner(
DynArrayIndex::<ElementType>::new(Expr::as_dyn_array(*this), Expr::as_dyn_int(index))
.to_expr()
.intern_sized(),
)
}
}
pub trait ExprIndex<I>: Type {
type Output: Type;
fn expr_index(this: &Expr<Self>, index: I) -> &Expr<Self::Output>;
}
impl<T: ExprIndex<I>, I> Index<I> for Expr<T> {
type Output = Expr<T::Output>;
#[track_caller]
fn index(&self, index: I) -> &Self::Output {
T::expr_index(self, index)
}
}
mod sealed {
pub trait BuiltInRangeSealed {}
}
pub trait BuiltInRange<T: ?Sized>: RangeBounds<T> + sealed::BuiltInRangeSealed {}
impl<I: ?Sized, T: RangeBounds<I> + ?Sized + sealed::BuiltInRangeSealed> BuiltInRange<I> for T {}
macro_rules! impl_built_in_range {
(<$T:ident> $ty:ty) => {
impl<$T> sealed::BuiltInRangeSealed for $ty {}
};
($ty:ty) => {
impl sealed::BuiltInRangeSealed for $ty {}
};
}
impl_built_in_range!(<T> (std::ops::Bound<T>, std::ops::Bound<T>));
impl_built_in_range!(<T> std::ops::Range<T>);
impl_built_in_range!(<T> std::ops::RangeFrom<T>);
impl_built_in_range!(std::ops::RangeFull);
impl_built_in_range!(<T> std::ops::RangeInclusive<T>);
impl_built_in_range!(<T> std::ops::RangeTo<T>);
impl_built_in_range!(<T> std::ops::RangeToInclusive<T>);
macro_rules! impl_int_slice {
($name:ident, $ty:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
base: Expr<$ty>,
range_start: usize,
range_end: usize,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
base,
range_start: _,
range_end: _,
literal_bits,
} = self;
f.debug_struct(stringify!($name))
.field("base", base)
.field("range", &self.range())
.field("literal_bits", literal_bits)
.finish()
}
}
impl $name {
pub fn new(base: Expr<$ty>, range: Range<usize>) -> Self {
assert!(
range.start <= range.end && range.end <= base.ty().width(),
"invalid range"
);
let literal_bits = base
.to_literal_bits()
.map(|bits| bits[range.clone()].intern());
Self {
base,
range_start: range.start,
range_end: range.end,
literal_bits,
}
}
pub fn base(self) -> Expr<$ty> {
self.base
}
pub fn range(self) -> Range<usize> {
self.range_start..self.range_end
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = UInt;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
UInt::new_dyn(self.range().len())
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<Width: Size, I: BuiltInRange<usize>> std::ops::Index<I> for Valueless<$ty<Width>> {
type Output = Valueless<UInt>;
#[track_caller]
fn index(&self, index: I) -> &Self::Output {
let range = self.ty().slice_index_to_range(index);
Interned::into_inner(Valueless::new(UInt::new_dyn(range.len())).intern_sized())
}
}
impl<Width: Size, I: BuiltInRange<usize>> ExprIndex<I> for $ty<Width> {
type Output = UInt;
#[track_caller]
fn expr_index(this: &Expr<Self>, index: I) -> &Expr<Self::Output> {
let base = Expr::as_dyn_int(*this);
let range = base.ty().slice_index_to_range(index);
Interned::into_inner($name::new(base, range).to_expr().intern_sized())
}
}
impl<Width: Size> std::ops::Index<usize> for Valueless<$ty<Width>> {
type Output = Valueless<Bool>;
#[track_caller]
fn index(&self, index: usize) -> &Self::Output {
assert!(index < self.ty().width());
&const { Valueless::new(Bool) }
}
}
impl<Width: Size> ExprIndex<usize> for $ty<Width> {
type Output = Bool;
#[track_caller]
fn expr_index(this: &Expr<Self>, index: usize) -> &Expr<Self::Output> {
let base = Expr::as_dyn_int(*this);
let base_ty = base.ty();
assert!(index < base_ty.width());
Interned::into_inner(
$name::new(base, index..(index + 1))
.to_expr()
.cast_to_static::<Bool>()
.intern_sized(),
)
}
}
};
}
impl_int_slice!(SliceUInt, UIntType);
impl_int_slice!(SliceSInt, SIntType);
macro_rules! impl_reduce_bits {
($name:ident, $ty:ident, |$bits:ident| $reduction_op:expr) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct $name {
arg: Expr<$ty>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl $name {
pub fn new(arg: Expr<$ty>) -> Self {
let literal_bits = arg.to_literal_bits().and_then(|$bits| $reduction_op);
Self { arg, literal_bits }
}
pub fn arg(self) -> Expr<$ty> {
self.arg
}
}
impl ToLiteralBits for $name {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] $name);
impl ValueType for $name {
type Type = UInt<1>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
StaticType::TYPE
}
}
impl ToExpr for $name {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::$name(*self).intern(),
__ty: UInt::<1>::TYPE,
__flow: Flow::Source,
}
}
}
};
}
impl_reduce_bits!(ReduceBitAndU, UInt, |bits| bits.all().to_literal_bits());
impl_reduce_bits!(ReduceBitAndS, SInt, |bits| bits.all().to_literal_bits());
impl_reduce_bits!(ReduceBitOrU, UInt, |bits| bits.any().to_literal_bits());
impl_reduce_bits!(ReduceBitOrS, SInt, |bits| bits.any().to_literal_bits());
impl_reduce_bits!(ReduceBitXorU, UInt, |bits| (bits.count_ones() % 2 != 0)
.to_literal_bits());
impl_reduce_bits!(ReduceBitXorS, SInt, |bits| (bits.count_ones() % 2 != 0)
.to_literal_bits());
impl<Width: Size> ReduceBitsImpl for UIntType<Width> {
fn value_reduce_bitand(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
value.bits().all().into()
}
fn value_reduce_bitor(_this: Self, value: Cow<'_, Self::SimValue>) -> UIntValue<ConstUsize<1>> {
value.bits().any().into()
}
fn value_reduce_bitxor(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
(value.bits().count_ones() % 2 != 0).into()
}
fn expr_reduce_bitand(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitAndU::new(Expr::as_dyn_int(this)).to_expr()
}
fn expr_reduce_bitor(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitOrU::new(Expr::as_dyn_int(this)).to_expr()
}
fn expr_reduce_bitxor(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitXorU::new(Expr::as_dyn_int(this)).to_expr()
}
}
impl<Width: Size> ReduceBitsImpl for SIntType<Width> {
fn value_reduce_bitand(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
value.bits().all().into()
}
fn value_reduce_bitor(_this: Self, value: Cow<'_, Self::SimValue>) -> UIntValue<ConstUsize<1>> {
value.bits().any().into()
}
fn value_reduce_bitxor(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
(value.bits().count_ones() % 2 != 0).into()
}
fn expr_reduce_bitand(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitAndS::new(Expr::as_dyn_int(this)).to_expr()
}
fn expr_reduce_bitor(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitOrS::new(Expr::as_dyn_int(this)).to_expr()
}
fn expr_reduce_bitxor(this: Expr<Self>) -> Expr<UInt<1>> {
ReduceBitXorS::new(Expr::as_dyn_int(this)).to_expr()
}
}
impl ReduceBitsImpl for Bool {
fn value_reduce_bitand(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
(*value).into()
}
fn value_reduce_bitor(_this: Self, value: Cow<'_, Self::SimValue>) -> UIntValue<ConstUsize<1>> {
(*value).into()
}
fn value_reduce_bitxor(
_this: Self,
value: Cow<'_, Self::SimValue>,
) -> UIntValue<ConstUsize<1>> {
(*value).into()
}
fn expr_reduce_bitand(this: Expr<Self>) -> Expr<UInt<1>> {
this.cast_to_static()
}
fn expr_reduce_bitor(this: Expr<Self>) -> Expr<UInt<1>> {
this.cast_to_static()
}
fn expr_reduce_bitxor(this: Expr<Self>) -> Expr<UInt<1>> {
this.cast_to_static()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct CastToBits {
arg: Expr<CanonicalType>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl CastToBits {
pub fn new(arg: Expr<CanonicalType>) -> Self {
Self {
arg,
literal_bits: arg.to_literal_bits(),
}
}
pub fn arg(self) -> Expr<CanonicalType> {
self.arg
}
}
impl ToLiteralBits for CastToBits {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] CastToBits);
impl ValueType for CastToBits {
type Type = UInt;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
UInt::new_dyn(self.arg.ty().bit_width())
}
}
impl ToExpr for CastToBits {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::CastToBits(*self).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct CastBitsTo<T: Type = CanonicalType> {
arg: Expr<UInt>,
ty: T,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl<T: Type> CastBitsTo<T> {
#[track_caller]
pub fn new(arg: Expr<UInt>, ty: T) -> Self {
let ty_props = ty.canonical().type_properties();
assert!(ty_props.is_castable_from_bits);
assert_eq!(arg.ty().width(), ty_props.bit_width);
Self {
arg,
ty,
literal_bits: arg.to_literal_bits(),
}
}
pub fn arg(self) -> Expr<UInt> {
self.arg
}
}
impl<T: Type> ToLiteralBits for CastBitsTo<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([T: Type] CastBitsTo<T>);
impl<T: Type> ValueType for CastBitsTo<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for CastBitsTo<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::CastBitsTo(CastBitsTo {
arg: self.arg,
ty: self.ty.canonical(),
literal_bits: self.literal_bits,
})
.intern(),
__ty: self.ty,
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Uninit<T: Type = CanonicalType> {
ty: T,
}
impl<T: Type> Uninit<T> {
#[track_caller]
pub fn new(ty: T) -> Self {
Self { ty }
}
}
impl<T: Type> ToLiteralBits for Uninit<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl_get_target_none!([T: Type] Uninit<T>);
impl<T: Type> ValueType for Uninit<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for Uninit<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Uninit(Uninit {
ty: self.ty.canonical(),
})
.intern(),
__ty: self.ty,
__flow: Flow::Source,
}
}
}
pub trait ExprIntoIterator: Type {
type Item: Type;
type ExprIntoIter: Iterator<Item = Expr<Self::Item>>;
fn expr_into_iter(e: Expr<Self>) -> Self::ExprIntoIter;
}
impl<T: ExprIntoIterator> IntoIterator for Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(self)
}
}
impl<T: ExprIntoIterator> IntoIterator for &'_ Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(*self)
}
}
impl<T: ExprIntoIterator> IntoIterator for &'_ mut Expr<T> {
type Item = Expr<T::Item>;
type IntoIter = T::ExprIntoIter;
fn into_iter(self) -> Self::IntoIter {
T::expr_into_iter(*self)
}
}
pub trait ExprFromIterator<A>: Type {
fn expr_from_iter<T: IntoIterator<Item = A>>(iter: T) -> Expr<Self>;
}
impl<This: ExprFromIterator<A>, A> FromIterator<A> for Expr<This> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
This::expr_from_iter(iter)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ToTraceAsString<T: Type = CanonicalType> {
inner: Expr<CanonicalType>,
ty: TraceAsString<T>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for ToTraceAsString<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
inner,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("ToTraceAsString")
.field("inner", inner)
.finish_non_exhaustive()
}
}
impl<T: Type> ToTraceAsString<T> {
pub fn new(inner: Expr<CanonicalType>, ty: TraceAsString<T>) -> Self {
assert_eq!(inner.ty(), ty.inner_ty().canonical());
let literal_bits = inner.to_literal_bits();
let target = inner.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathToTraceAsString {
ty: ty.canonical_trace_as_string(),
}
.into(),
))
.canonicalized(),
)
});
Self {
inner,
ty,
literal_bits,
target,
}
}
pub fn inner(self) -> Expr<CanonicalType> {
self.inner
}
}
impl<T: Type> GetTarget for ToTraceAsString<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for ToTraceAsString<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for ToTraceAsString<T> {
type Type = TraceAsString<T>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for ToTraceAsString<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ToTraceAsString(ToTraceAsString {
inner: self.inner,
ty: self.ty.canonical_trace_as_string(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.inner),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TraceAsStringAsInner<T: Type = CanonicalType> {
arg: Expr<TraceAsString<CanonicalType>>,
ty: T,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for TraceAsStringAsInner<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
arg,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("TraceAsStringAsInner")
.field("arg", arg)
.finish_non_exhaustive()
}
}
impl<T: Type> TraceAsStringAsInner<T> {
pub fn from_arg_and_ty(arg: Expr<TraceAsString<CanonicalType>>, ty: T) -> Self {
assert_eq!(arg.ty().inner_ty(), ty.canonical());
let literal_bits = arg.to_literal_bits();
let target = arg.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathTraceAsStringInner {}.into(),
))
.canonicalized(),
)
});
Self {
arg,
ty,
literal_bits,
target,
}
}
pub fn new(arg: Expr<TraceAsString<T>>) -> Self {
Self::from_arg_and_ty(
Expr {
__enum: arg.__enum,
__ty: arg.__ty.canonical_trace_as_string(),
__flow: arg.__flow,
},
arg.ty().inner_ty(),
)
}
pub fn arg(self) -> Expr<TraceAsString<CanonicalType>> {
self.arg
}
pub fn arg_typed(self) -> Expr<TraceAsString<T>> {
Expr {
__enum: self.arg.__enum,
__ty: TraceAsString::from_canonical_trace_as_string(self.arg.__ty),
__flow: self.arg.__flow,
}
}
}
impl<T: Type> GetTarget for TraceAsStringAsInner<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for TraceAsStringAsInner<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for TraceAsStringAsInner<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for TraceAsStringAsInner<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::TraceAsStringAsInner(TraceAsStringAsInner {
arg: self.arg,
ty: self.ty.canonical(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.arg),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
/// The [`Simulation::io()`] equivalent for a global signal, this is a flipped version of a global signal that allows you to e.g. use [`Simulation::write()`] to write to [`formal_global_clock()`]
pub struct SimIoForGlobal {
global: FormalInput,
}
impl fmt::Debug for SimIoForGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimIoForGlobal").field(&self.global).finish()
}
}
impl SimIoForGlobal {
pub fn new(global: FormalInput) -> Self {
Self { global }
}
pub fn global(self) -> FormalInput {
self.global
}
pub(crate) fn must_connect_to(self) -> bool {
true
}
pub fn flow(self) -> Flow {
self.global.flow().flip()
}
pub(crate) fn source_location(self) -> crate::source_location::SourceLocation {
self.global.source_location()
}
}
impl GetTarget for SimIoForGlobal {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::from(*self).intern_sized())
}
}
impl ToLiteralBits for SimIoForGlobal {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl ValueType for SimIoForGlobal {
type Type = CanonicalType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.global.ty()
}
}
impl ToExpr for SimIoForGlobal {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::SimIoForGlobal(*self).intern(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}