forked from libre-chip/fayalite
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.
4945 lines
154 KiB
Rust
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(),
|
|
}
|
|
}
|
|
}
|