fayalite::expr::ops: add and automatically generate ops::StructuralEq
This commit is contained in:
parent
ffca1a279d
commit
98e7e91fc9
18 changed files with 1030 additions and 220 deletions
|
|
@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle {
|
|||
let mut fields_expr_ne = vec![];
|
||||
let mut fields_valueless_eq = vec![];
|
||||
let mut fields_valueless_ne = vec![];
|
||||
let mut fields_structural_eq = vec![];
|
||||
for field in fields.named() {
|
||||
let field_ident = field.ident();
|
||||
let field_ty = field.ty();
|
||||
|
|
@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle {
|
|||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||
});
|
||||
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
|
||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
fields_value_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||
__lhs.#field_ident,
|
||||
|
|
@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle {
|
|||
let expr_ne_body;
|
||||
let valueless_eq_body;
|
||||
let valueless_ne_body;
|
||||
let structural_eq;
|
||||
if fields_len == 0 {
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
true
|
||||
|
|
@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle {
|
|||
valueless_ne_body = quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
};
|
||||
structural_eq = quote_spanned! {span=>
|
||||
true
|
||||
};
|
||||
} else {
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
#(#fields_value_eq)&*
|
||||
|
|
@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle {
|
|||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_ne)|*
|
||||
};
|
||||
structural_eq = quote_spanned! {span=>
|
||||
#(#fields_structural_eq)&&*
|
||||
};
|
||||
};
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||
#cmp_eq_where_clause
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
__lhs: Self,
|
||||
|
|
@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle {
|
|||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||
::fayalite::expr::ops::StructuralEq::try_new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
)
|
||||
{
|
||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||
}
|
||||
}
|
||||
#expr_eq_body
|
||||
}
|
||||
|
||||
|
|
@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle {
|
|||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
return !::fayalite::expr::ToExpr::to_expr(
|
||||
&::fayalite::expr::ops::StructuralEq::new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
),
|
||||
);
|
||||
}
|
||||
#expr_ne_body
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum {
|
|||
#where_clause
|
||||
{
|
||||
#[allow(non_snake_case, dead_code)]
|
||||
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
#vis fn #ident(
|
||||
#self_token,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
#self_token.#sim_builder_ty_field_ident,
|
||||
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
||||
|
|
@ -929,8 +931,14 @@ impl ToTokens for ParsedEnum {
|
|||
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
|
||||
fn fmt(
|
||||
&self,
|
||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
||||
) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
|
||||
self,
|
||||
f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}.to_tokens(tokens);
|
||||
|
|
@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum {
|
|||
let mut variants_value_eq = vec![];
|
||||
let mut variants_expr_eq = vec![];
|
||||
let mut fields_valueless_eq = vec![];
|
||||
let mut structural_eq: Option<TokenStream> = None;
|
||||
for (
|
||||
variant_index,
|
||||
ParsedVariant {
|
||||
|
|
@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum {
|
|||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||
});
|
||||
match &mut structural_eq {
|
||||
Some(structural_eq) => {
|
||||
structural_eq.extend(quote_spanned! {cmp_eq.span=>
|
||||
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
}
|
||||
None => {
|
||||
structural_eq = Some(quote_spanned! {cmp_eq.span=>
|
||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
||||
});
|
||||
}
|
||||
}
|
||||
variants_value_eq.push(quote_spanned! {span=>
|
||||
(#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => {
|
||||
(
|
||||
#sim_value_ident::#variant_ident(__lhs_field, _),
|
||||
#sim_value_ident::#variant_ident(__rhs_field, _),
|
||||
) => {
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||
__lhs.#variant_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
||||
|
|
@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum {
|
|||
else {
|
||||
::fayalite::__std::unreachable!();
|
||||
};
|
||||
::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs));
|
||||
::fayalite::module::connect(
|
||||
__retval,
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
|
||||
);
|
||||
}
|
||||
});
|
||||
fields_valueless_eq.push(quote_spanned! {span=>
|
||||
|
|
@ -1043,7 +1070,10 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||
variants_value_eq.push(quote_spanned! {span=>
|
||||
(#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => {
|
||||
(
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
|
||||
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
|
||||
) => {
|
||||
__lhs_unknown == __rhs_unknown
|
||||
}
|
||||
});
|
||||
|
|
@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
};
|
||||
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
||||
let structural_eq = structural_eq.unwrap_or_else(|| {
|
||||
quote_spanned! {span=>
|
||||
true
|
||||
}
|
||||
});
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||
#cmp_eq_where_clause
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
|
||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
|
||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
match (&*__lhs_value, &*__rhs_value) {
|
||||
#(#variants_value_eq)*
|
||||
|
|
@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum {
|
|||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool);
|
||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
||||
::fayalite::expr::ops::StructuralEq::try_new(
|
||||
::fayalite::expr::Expr::canonical(__lhs),
|
||||
::fayalite::expr::Expr::canonical(__rhs),
|
||||
)
|
||||
{
|
||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
||||
}
|
||||
}
|
||||
let __retval = ::fayalite::module::wire(
|
||||
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
|
||||
::fayalite::int::Bool,
|
||||
);
|
||||
::fayalite::module::connect(__retval, false);
|
||||
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
||||
#(#variants_expr_eq)*
|
||||
|
|
@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum {
|
|||
type SimValue = #sim_value_ident #type_generics;
|
||||
type MatchVariant = #match_variant_ident #type_generics;
|
||||
type MatchActiveScope = ::fayalite::module::Scope;
|
||||
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||
type MatchVariantAndInactiveScope =
|
||||
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
||||
|
||||
fn match_variants(
|
||||
|
|
@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum {
|
|||
::fayalite::int::Bool
|
||||
}
|
||||
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
||||
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
|
||||
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
|
||||
::fayalite::enum_::EnumType::variants(#self_token),
|
||||
))
|
||||
}
|
||||
#[track_caller]
|
||||
#[allow(non_snake_case)]
|
||||
|
|
@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum {
|
|||
::fayalite::__std::panic!("expected enum");
|
||||
};
|
||||
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
|
||||
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
|
||||
::fayalite::__std::assert_eq!(
|
||||
#variants_token.len(),
|
||||
#variants_len,
|
||||
"enum has wrong number of variants",
|
||||
);
|
||||
Self {
|
||||
#(#from_canonical_body_fields)*
|
||||
}
|
||||
|
|
@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum {
|
|||
type SimBuilder = #sim_builder_ident #type_generics;
|
||||
fn match_activate_scope(
|
||||
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
||||
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
|
||||
) -> (
|
||||
<Self as ::fayalite::ty::Type>::MatchVariant,
|
||||
<Self as ::fayalite::ty::Type>::MatchActiveScope,
|
||||
) {
|
||||
let (#variant_access_token, scope) = v.activate();
|
||||
(
|
||||
match #variant_access_token.variant_index() {
|
||||
|
|
@ -1200,7 +1262,10 @@ impl ToTokens for ParsedEnum {
|
|||
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||
fn fmt(
|
||||
&self,
|
||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
||||
) -> ::fayalite::__std::fmt::Result {
|
||||
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||
}
|
||||
}
|
||||
|
|
@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum {
|
|||
&self,
|
||||
ty: #target #type_generics,
|
||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
ty,
|
||||
::fayalite::__std::clone::Clone::clone(self),
|
||||
)
|
||||
}
|
||||
fn into_sim_value_with_type(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
|
|||
where
|
||||
Lhs: HdlPartialEqImpl<Rhs>,
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::TRY_STRUCTURAL_EQ;
|
||||
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
|
|
|
|||
|
|
@ -708,6 +708,8 @@ macro_rules! impl_tuples {
|
|||
}
|
||||
}
|
||||
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||
const TRY_STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::TRY_STRUCTURAL_EQ)*;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ expr_enum! {
|
|||
CastBitsTo(ops::CastBitsTo),
|
||||
ToTraceAsString(ops::ToTraceAsString),
|
||||
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
||||
StructuralEq(ops::StructuralEq),
|
||||
ModuleIO(ModuleIO<CanonicalType>),
|
||||
Instance(Instance<Bundle>),
|
||||
Wire(Wire<CanonicalType>),
|
||||
|
|
@ -701,6 +702,7 @@ macro_rules! impl_hdl_cmp {
|
|||
impl_helper = $HdlCmpImplHelper:ident,
|
||||
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
||||
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
||||
$(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)?
|
||||
]
|
||||
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
||||
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
||||
|
|
@ -729,6 +731,8 @@ macro_rules! impl_hdl_cmp {
|
|||
}
|
||||
|
||||
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
||||
$(const $TRY_STRUCTURAL_EQ: bool;)?
|
||||
|
||||
$(#[track_caller]
|
||||
fn $cmp_value_fn(
|
||||
$cmp_value_lhs: Self,
|
||||
|
|
@ -912,6 +916,7 @@ impl_hdl_cmp! {
|
|||
#[
|
||||
impl_helper = HdlPartialEqImplHelper,
|
||||
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
||||
try_structural_eq = TRY_STRUCTURAL_EQ,
|
||||
]
|
||||
pub trait HdlPartialEq<Rhs: ValueType>:
|
||||
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
||||
UIntType, UIntValue,
|
||||
},
|
||||
intern::{Intern, Interned},
|
||||
intern::{Intern, Interned, MemoizeGeneric},
|
||||
phantom_const::{PhantomConst, PhantomConstValue},
|
||||
reset::{
|
||||
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
||||
|
|
@ -2984,6 +2984,7 @@ macro_rules! impl_compare_op {
|
|||
#[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)]
|
||||
$(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])?
|
||||
#[trait($Trait:ident)]
|
||||
$(
|
||||
struct $name:ident;
|
||||
|
|
@ -3045,6 +3046,7 @@ macro_rules! impl_compare_op {
|
|||
})*
|
||||
|
||||
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
||||
$(const $TRY_STRUCTURAL_EQ: bool = true;)?
|
||||
$(fn $value_method(
|
||||
_lhs: Self,
|
||||
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
|
|
@ -3065,6 +3067,7 @@ impl_compare_op! {
|
|||
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
||||
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
||||
#[type(Bool, Bool)]
|
||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||
#[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();
|
||||
|
|
@ -3088,6 +3091,7 @@ impl_compare_op! {
|
|||
#[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>)]
|
||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||
#[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();
|
||||
|
|
@ -3112,6 +3116,7 @@ impl_compare_op! {
|
|||
#[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>)]
|
||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||
#[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();
|
||||
|
|
@ -3133,6 +3138,8 @@ impl_compare_op! {
|
|||
macro_rules! impl_compare_forwards_to_bool {
|
||||
($ty:ident) => {
|
||||
impl HdlPartialEqImpl<Self> for $ty {
|
||||
const TRY_STRUCTURAL_EQ: bool = true;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
|
|
@ -4948,3 +4955,270 @@ impl ToExpr for SimIoForGlobal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct StructuralEqFlags {
|
||||
pub assume_padding_is_zeroed: bool,
|
||||
}
|
||||
|
||||
impl StructuralEqFlags {
|
||||
pub const DEFAULT: Self = Self {
|
||||
assume_padding_is_zeroed: false,
|
||||
};
|
||||
}
|
||||
|
||||
impl Default for StructuralEqFlags {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum StructuralEqError {
|
||||
TypesAreNotEqual {
|
||||
lhs: CanonicalType,
|
||||
rhs: CanonicalType,
|
||||
},
|
||||
TypeContainsSimOnly {
|
||||
ty: CanonicalType,
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for StructuralEqError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::TypesAreNotEqual { lhs, rhs } => write!(
|
||||
f,
|
||||
"StructuralEq lhs type must be the same as rhs type:\nlhs: {lhs:#?}\nrhs: {rhs:#?}\n",
|
||||
),
|
||||
Self::TypeContainsSimOnly { ty } => write!(
|
||||
f,
|
||||
"StructuralEq input type must not contain SimOnly type: {ty:#?}",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct StructuralEq {
|
||||
lhs: Expr<CanonicalType>,
|
||||
rhs: Expr<CanonicalType>,
|
||||
flags: StructuralEqFlags,
|
||||
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
|
||||
}
|
||||
|
||||
impl StructuralEq {
|
||||
fn literal_eq(
|
||||
ty: CanonicalType,
|
||||
l: Interned<BitSlice>,
|
||||
r: Interned<BitSlice>,
|
||||
) -> Result<bool, NotALiteralExpr> {
|
||||
enum PairRefOrInternedBitSlice<'a> {
|
||||
Ref(&'a BitSlice, &'a BitSlice),
|
||||
Interned(Interned<BitSlice>, Interned<BitSlice>),
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct MyMemoize(CanonicalType);
|
||||
impl MemoizeGeneric for MyMemoize {
|
||||
type InputRef<'a> = (&'a BitSlice, &'a BitSlice);
|
||||
type InputOwned = (Interned<BitSlice>, Interned<BitSlice>);
|
||||
type InputCow<'a> = PairRefOrInternedBitSlice<'a>;
|
||||
type Output = Result<bool, NotALiteralExpr>;
|
||||
|
||||
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
|
||||
a == b
|
||||
}
|
||||
|
||||
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
||||
let (l, r) = input;
|
||||
(l, r)
|
||||
}
|
||||
|
||||
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
|
||||
match input {
|
||||
PairRefOrInternedBitSlice::Ref(l, r) => (l.intern(), r.intern()),
|
||||
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
|
||||
match input {
|
||||
PairRefOrInternedBitSlice::Ref(l, r) => (l, r),
|
||||
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
|
||||
}
|
||||
}
|
||||
|
||||
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
|
||||
let (l, r) = input;
|
||||
PairRefOrInternedBitSlice::Interned(l, r)
|
||||
}
|
||||
|
||||
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
|
||||
let (l, r) = input;
|
||||
PairRefOrInternedBitSlice::Ref(l, r)
|
||||
}
|
||||
|
||||
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
|
||||
let (mut l, mut r) = input;
|
||||
match self.0 {
|
||||
CanonicalType::UInt(_)
|
||||
| CanonicalType::SInt(_)
|
||||
| CanonicalType::Bool(_)
|
||||
| CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_)
|
||||
| CanonicalType::PhantomConst(_) => Ok(l == r),
|
||||
CanonicalType::Array(ty) => {
|
||||
let element_ty = ty.element();
|
||||
let element_bit_width = element_ty.bit_width();
|
||||
let mut eq = true;
|
||||
for element_index in 0..ty.len() {
|
||||
if !Self(element_ty).get((
|
||||
&l[element_bit_width * element_index..][..element_bit_width],
|
||||
&r[element_bit_width * element_index..][..element_bit_width],
|
||||
))? {
|
||||
eq = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(eq)
|
||||
}
|
||||
CanonicalType::Enum(ty) => {
|
||||
let discriminant_bit_width = ty.discriminant_bit_width();
|
||||
let (l_discriminant_bits, l_body_bits) = l.split_at(discriminant_bit_width);
|
||||
let (r_discriminant_bits, r_body_bits) = r.split_at(discriminant_bit_width);
|
||||
if l_discriminant_bits != r_discriminant_bits {
|
||||
return Ok(false);
|
||||
}
|
||||
let mut discriminant = 0usize;
|
||||
discriminant.view_bits_mut::<Lsb0>()[..l_discriminant_bits.len()]
|
||||
.copy_from_bitslice(l_discriminant_bits);
|
||||
match ty.variants().get(discriminant) {
|
||||
Some(&EnumVariant {
|
||||
name: _,
|
||||
ty: Some(variant_ty),
|
||||
}) => {
|
||||
let variant_bit_width = variant_ty.bit_width();
|
||||
Self(variant_ty).get((
|
||||
&l_body_bits[..variant_bit_width],
|
||||
&r_body_bits[..variant_bit_width],
|
||||
))
|
||||
}
|
||||
Some(EnumVariant { name: _, ty: None }) => Ok(true),
|
||||
None => Err(NotALiteralExpr),
|
||||
}
|
||||
}
|
||||
CanonicalType::Bundle(ty) => {
|
||||
let mut eq = true;
|
||||
for field in &ty.fields() {
|
||||
let field_bit_width = field.ty.bit_width();
|
||||
let l_field;
|
||||
let r_field;
|
||||
(l_field, l) = l.split_at(field_bit_width);
|
||||
(r_field, r) = r.split_at(field_bit_width);
|
||||
if !Self(field.ty).get((l_field, r_field))? {
|
||||
eq = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(eq)
|
||||
}
|
||||
CanonicalType::DynSimOnly(_) => unreachable!("doesn't have literal_bits"),
|
||||
CanonicalType::TraceAsString(ty) => Self(ty.inner_ty()).get((l, r)),
|
||||
}
|
||||
}
|
||||
}
|
||||
MyMemoize(ty).get_owned((l, r))
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn new(lhs: Expr<CanonicalType>, rhs: Expr<CanonicalType>) -> Self {
|
||||
Self::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn with_flags(
|
||||
lhs: Expr<CanonicalType>,
|
||||
rhs: Expr<CanonicalType>,
|
||||
flags: StructuralEqFlags,
|
||||
) -> Self {
|
||||
match Self::try_with_flags(lhs, rhs, flags) {
|
||||
Ok(retval) => retval,
|
||||
Err(e) => panic!("{e}"),
|
||||
}
|
||||
}
|
||||
pub fn try_new(
|
||||
lhs: Expr<CanonicalType>,
|
||||
rhs: Expr<CanonicalType>,
|
||||
) -> Result<Self, StructuralEqError> {
|
||||
Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
||||
}
|
||||
pub fn try_with_flags(
|
||||
lhs: Expr<CanonicalType>,
|
||||
rhs: Expr<CanonicalType>,
|
||||
flags: StructuralEqFlags,
|
||||
) -> Result<Self, StructuralEqError> {
|
||||
let ty = lhs.ty();
|
||||
let rhs_ty = rhs.ty();
|
||||
if ty != rhs_ty {
|
||||
return Err(StructuralEqError::TypesAreNotEqual {
|
||||
lhs: ty,
|
||||
rhs: rhs_ty,
|
||||
});
|
||||
}
|
||||
if ty.contains_sim_only() {
|
||||
return Err(StructuralEqError::TypeContainsSimOnly { ty });
|
||||
}
|
||||
Ok(Self {
|
||||
lhs,
|
||||
rhs,
|
||||
flags,
|
||||
literal_bits: lhs.to_literal_bits().and_then(|lhs| {
|
||||
let rhs = rhs.to_literal_bits()?;
|
||||
if flags.assume_padding_is_zeroed {
|
||||
lhs == rhs
|
||||
} else {
|
||||
Self::literal_eq(ty, lhs, rhs)?
|
||||
}
|
||||
.to_literal_bits()
|
||||
}),
|
||||
})
|
||||
}
|
||||
pub fn lhs(self) -> Expr<CanonicalType> {
|
||||
self.lhs
|
||||
}
|
||||
pub fn rhs(self) -> Expr<CanonicalType> {
|
||||
self.rhs
|
||||
}
|
||||
pub fn flags(self) -> StructuralEqFlags {
|
||||
self.flags
|
||||
}
|
||||
}
|
||||
|
||||
impl ToLiteralBits for StructuralEq {
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
||||
impl_get_target_none!([] StructuralEq);
|
||||
|
||||
impl ValueType for StructuralEq {
|
||||
type Type = Bool;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
Bool
|
||||
}
|
||||
}
|
||||
|
||||
impl ToExpr for StructuralEq {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
Expr {
|
||||
__enum: ExprEnum::StructuralEq(*self).intern(),
|
||||
__ty: Bool,
|
||||
__flow: Flow::Source,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
bundle::{BundleField, BundleType},
|
||||
enum_::{EnumType, EnumVariant},
|
||||
expr::{
|
||||
ExprEnum,
|
||||
CastToImpl, ExprEnum,
|
||||
ops::{self, VariantAccess},
|
||||
target::{
|
||||
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
||||
|
|
@ -389,6 +389,7 @@ struct BlockDefinitionsCache {
|
|||
cast_bits_to_array_exprs: RefCell<HashMap<(String, Array), String>>,
|
||||
cast_bits_to_phantom_const_exprs: RefCell<HashMap<(String, PhantomConst), String>>,
|
||||
per_module_formal_inputs: RefCell<HashMap<(FormalInput, bool), String>>,
|
||||
structural_eq_exprs: RefCell<HashMap<(String, String), String>>,
|
||||
}
|
||||
|
||||
struct BlockDefinitions<'a> {
|
||||
|
|
@ -1774,6 +1775,143 @@ endmodule
|
|||
},
|
||||
)
|
||||
}
|
||||
fn expr_structural_eq_bit<T: CastToImpl<Bool>>(
|
||||
&mut self,
|
||||
lhs: Expr<CanonicalType>,
|
||||
rhs: Expr<CanonicalType>,
|
||||
definitions: &BlockDefinitions<'_>,
|
||||
const_ty: bool,
|
||||
) -> Result<String> {
|
||||
self.expr_binary(
|
||||
"eq",
|
||||
Expr::<T>::from_canonical(lhs).cast_to(Bool),
|
||||
Expr::<T>::from_canonical(rhs).cast_to(Bool),
|
||||
definitions,
|
||||
const_ty,
|
||||
)
|
||||
}
|
||||
fn expr_structural_eq(
|
||||
&mut self,
|
||||
ty: CanonicalType,
|
||||
lhs: String,
|
||||
rhs: String,
|
||||
definitions: &BlockDefinitions<'_>,
|
||||
const_ty: bool,
|
||||
) -> Result<String> {
|
||||
match ty {
|
||||
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
|
||||
Ok(format!("eq({lhs}, {rhs})"))
|
||||
}
|
||||
CanonicalType::Array(ty) => {
|
||||
if ty.len() == 1 {
|
||||
return self.expr_structural_eq(
|
||||
ty.element(),
|
||||
lhs + "[0]",
|
||||
rhs + "[0]",
|
||||
definitions,
|
||||
const_ty,
|
||||
);
|
||||
} else if ty.is_empty() {
|
||||
return Ok(self.bool_literal(true));
|
||||
}
|
||||
definitions.get_or_write_definition(
|
||||
(lhs, rhs),
|
||||
|c| &c.structural_eq_exprs,
|
||||
|definitions, (lhs, rhs)| {
|
||||
let mut retval = None;
|
||||
for array_index in 0..ty.len() {
|
||||
let element_eq = self.expr_structural_eq(
|
||||
ty.element(),
|
||||
format!("{lhs}[{array_index}]"),
|
||||
format!("{rhs}[{array_index}]"),
|
||||
&definitions,
|
||||
const_ty,
|
||||
)?;
|
||||
retval = match retval {
|
||||
Some(old_eq) => {
|
||||
let ident = self.module.ns.make_new("_array_structural_eq");
|
||||
definitions
|
||||
.add_definition_line(format_args!("wire {ident}: UInt<1>"));
|
||||
definitions.add_definition_line(format_args!(
|
||||
"connect {ident}, and({old_eq}, {element_eq})"
|
||||
));
|
||||
Some(ident.to_string())
|
||||
}
|
||||
None => Some(element_eq),
|
||||
};
|
||||
}
|
||||
Ok(retval.expect("known to be Some"))
|
||||
},
|
||||
)
|
||||
}
|
||||
CanonicalType::Enum(ty) => {
|
||||
let lhs = self.expr_cast_enum_to_bits(
|
||||
lhs,
|
||||
ty,
|
||||
definitions,
|
||||
Indent {
|
||||
indent_depth: &Cell::new(0),
|
||||
indent: self.indent.indent,
|
||||
},
|
||||
)?;
|
||||
let rhs = self.expr_cast_enum_to_bits(
|
||||
rhs,
|
||||
ty,
|
||||
definitions,
|
||||
Indent {
|
||||
indent_depth: &Cell::new(0),
|
||||
indent: self.indent.indent,
|
||||
},
|
||||
)?;
|
||||
Ok(format!("eq({lhs}, {rhs})"))
|
||||
}
|
||||
CanonicalType::Bundle(ty) => {
|
||||
let fields = ty.fields();
|
||||
if fields.is_empty() {
|
||||
return Ok(self.bool_literal(true));
|
||||
}
|
||||
definitions.get_or_write_definition(
|
||||
(lhs, rhs),
|
||||
|c| &c.structural_eq_exprs,
|
||||
|definitions, (lhs, rhs)| {
|
||||
let mut retval = None;
|
||||
for field in fields {
|
||||
let field_ident = self.type_state.get_bundle_field(ty, field.name)?;
|
||||
let field_eq = self.expr_structural_eq(
|
||||
field.ty,
|
||||
format!("{lhs}.{field_ident}"),
|
||||
format!("{rhs}.{field_ident}"),
|
||||
&definitions,
|
||||
const_ty,
|
||||
)?;
|
||||
retval = match retval {
|
||||
Some(old_eq) => {
|
||||
let ident = self.module.ns.make_new("_bundle_structural_eq");
|
||||
definitions
|
||||
.add_definition_line(format_args!("wire {ident}: UInt<1>"));
|
||||
definitions.add_definition_line(format_args!(
|
||||
"connect {ident}, and({old_eq}, {field_eq})"
|
||||
));
|
||||
Some(ident.to_string())
|
||||
}
|
||||
None => Some(field_eq),
|
||||
};
|
||||
}
|
||||
Ok(retval.expect("known to be Some"))
|
||||
},
|
||||
)
|
||||
}
|
||||
CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_) => Ok(format!("eq(asUInt({lhs}), asUInt({rhs}))")),
|
||||
CanonicalType::PhantomConst(_) => Ok(self.bool_literal(true)),
|
||||
CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()),
|
||||
CanonicalType::TraceAsString(ty) => {
|
||||
self.expr_structural_eq(ty.inner_ty(), lhs, rhs, definitions, const_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn expr(
|
||||
&mut self,
|
||||
expr: Expr<CanonicalType>,
|
||||
|
|
@ -2117,6 +2255,13 @@ endmodule
|
|||
ExprEnum::TraceAsStringAsInner(expr) => {
|
||||
self.expr(Expr::canonical(expr.arg()), definitions, const_ty)
|
||||
}
|
||||
ExprEnum::StructuralEq(expr) => {
|
||||
let ty = expr.lhs().ty();
|
||||
assert_eq!(ty, expr.rhs().ty());
|
||||
let lhs = self.expr(expr.lhs(), definitions, const_ty)?;
|
||||
let rhs = self.expr(expr.rhs(), definitions, const_ty)?;
|
||||
self.expr_structural_eq(ty, lhs, rhs, definitions, const_ty)
|
||||
}
|
||||
ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()),
|
||||
ExprEnum::Instance(expr) => {
|
||||
assert!(!const_ty, "not a constant");
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
|
|||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
||||
const TRY_STRUCTURAL_EQ: bool = true;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
|
|
@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type {
|
|||
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: bool = true;
|
||||
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
|
|
@ -657,6 +661,8 @@ macro_rules! define_uint_in_range_type {
|
|||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
||||
for $UIntInRangeType<Start, End>
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: bool = false;
|
||||
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
|
|
@ -676,6 +682,8 @@ macro_rules! define_uint_in_range_type {
|
|||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
||||
for UIntType<Width>
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: bool = false;
|
||||
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
|
|
|
|||
|
|
@ -2206,6 +2206,7 @@ impl transform::visit::Visitor for AssertExprValidity<'_> {
|
|||
| ExprEnum::CastBitsTo(_)
|
||||
| ExprEnum::ToTraceAsString(_)
|
||||
| ExprEnum::TraceAsStringAsInner(_)
|
||||
| ExprEnum::StructuralEq(_)
|
||||
| ExprEnum::FormalInput(_) => v.default_visit(self),
|
||||
ExprEnum::VariantAccess(_)
|
||||
| ExprEnum::ModuleIO(_)
|
||||
|
|
|
|||
|
|
@ -1208,6 +1208,7 @@ impl<P: Pass> RunPass<P> for ExprEnum {
|
|||
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
||||
}
|
||||
ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||
ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||
ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||
ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||
|
|
@ -1653,6 +1654,35 @@ impl RunPassExpr for ops::ToTraceAsString {
|
|||
}
|
||||
}
|
||||
|
||||
impl RunPassExpr for ops::StructuralEq {
|
||||
type Args<'a> = [Expr<CanonicalType>; 2];
|
||||
|
||||
fn args<'a>(&'a self) -> Self::Args<'a> {
|
||||
[self.lhs(), self.rhs()]
|
||||
}
|
||||
|
||||
fn source_location(&self) -> Option<SourceLocation> {
|
||||
None
|
||||
}
|
||||
|
||||
fn union_parts(
|
||||
&self,
|
||||
_resets: Resets,
|
||||
args_resets: Vec<Resets>,
|
||||
mut pass_args: PassArgs<'_, BuildResetGraph>,
|
||||
) -> Result<(), DeduceResetsError> {
|
||||
pass_args.union(args_resets[0], args_resets[1], None)
|
||||
}
|
||||
|
||||
fn new(
|
||||
&self,
|
||||
_ty: CanonicalType,
|
||||
new_args: Vec<Expr<CanonicalType>>,
|
||||
) -> Result<Self, DeduceResetsError> {
|
||||
Ok(Self::with_flags(new_args[0], new_args[1], self.flags()))
|
||||
}
|
||||
}
|
||||
|
||||
impl RunPassExpr for ModuleIO<CanonicalType> {
|
||||
type Args<'a> = [Expr<CanonicalType>; 0];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,23 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
array::{Array, ArrayType},
|
||||
bundle::{Bundle, BundleField, BundleType},
|
||||
enum_::{Enum, EnumType, EnumVariant},
|
||||
bundle::{BundleField, BundleType},
|
||||
enum_::{EnumType, EnumVariant},
|
||||
expr::{
|
||||
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
|
||||
ops::{self, EnumLiteral},
|
||||
ExprEnum,
|
||||
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
|
||||
},
|
||||
hdl,
|
||||
int::UInt,
|
||||
intern::{Intern, InternSlice, Interned, Memoize},
|
||||
memory::{DynPortType, Mem, MemPort},
|
||||
memory::{DynPortType, MemPort},
|
||||
module::{
|
||||
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
||||
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
||||
transform::visit::{Fold, Folder},
|
||||
},
|
||||
source_location::SourceLocation,
|
||||
ty::{CanonicalType, TraceAsString, Type},
|
||||
prelude::*,
|
||||
util::HashMap,
|
||||
wire::Wire,
|
||||
};
|
||||
use core::fmt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SimplifyEnumsError {
|
||||
|
|
@ -97,6 +92,7 @@ enum EnumTypeState {
|
|||
struct ModuleState {
|
||||
module_name: NameId,
|
||||
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
||||
source_location: SourceLocation,
|
||||
}
|
||||
|
||||
impl ModuleState {
|
||||
|
|
@ -110,6 +106,45 @@ struct State {
|
|||
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
||||
kind: SimplifyEnumsKind,
|
||||
module_state_stack: Vec<ModuleState>,
|
||||
new_prefix_stmts_for_block: Vec<Stmt>,
|
||||
new_suffix_stmts_for_block: Vec<Stmt>,
|
||||
}
|
||||
|
||||
struct BlockScope<'a> {
|
||||
state: &'a mut State,
|
||||
parent_new_prefix_stmts_for_block: Vec<Stmt>,
|
||||
parent_new_suffix_stmts_for_block: Vec<Stmt>,
|
||||
}
|
||||
|
||||
impl<'a> BlockScope<'a> {
|
||||
fn new(
|
||||
state: &'a mut State,
|
||||
new_prefix_stmts_for_block: Vec<Stmt>,
|
||||
new_suffix_stmts_for_block: Vec<Stmt>,
|
||||
) -> Self {
|
||||
let parent_new_prefix_stmts_for_block = std::mem::replace(
|
||||
&mut state.new_prefix_stmts_for_block,
|
||||
new_prefix_stmts_for_block,
|
||||
);
|
||||
let parent_new_suffix_stmts_for_block = std::mem::replace(
|
||||
&mut state.new_suffix_stmts_for_block,
|
||||
new_suffix_stmts_for_block,
|
||||
);
|
||||
Self {
|
||||
state,
|
||||
parent_new_prefix_stmts_for_block,
|
||||
parent_new_suffix_stmts_for_block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BlockScope<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.state.new_prefix_stmts_for_block =
|
||||
std::mem::take(&mut self.parent_new_prefix_stmts_for_block);
|
||||
self.state.new_suffix_stmts_for_block =
|
||||
std::mem::take(&mut self.parent_new_suffix_stmts_for_block);
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
|
@ -549,6 +584,185 @@ impl State {
|
|||
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn handle_enum_structural_eq(
|
||||
&mut self,
|
||||
unfolded_ty: Enum,
|
||||
folded_lhs: Expr<CanonicalType>,
|
||||
folded_rhs: Expr<CanonicalType>,
|
||||
flags: StructuralEqFlags,
|
||||
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
||||
if flags.assume_padding_is_zeroed {
|
||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
||||
}
|
||||
let enum_type_state = self.get_or_make_enum_type_state(unfolded_ty)?;
|
||||
if let EnumTypeState::Unchanged = enum_type_state {
|
||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
||||
}
|
||||
let module_state = self.module_state_stack.last_mut().unwrap();
|
||||
let source_location = module_state.source_location;
|
||||
let output_wire = Wire::new_unchecked(
|
||||
module_state.gen_name("__enum_structural_eq"),
|
||||
source_location,
|
||||
Bool,
|
||||
);
|
||||
self.new_prefix_stmts_for_block.push(
|
||||
StmtWire {
|
||||
annotations: Interned::default(),
|
||||
wire: output_wire.canonical(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
let output_wire = output_wire.to_expr();
|
||||
self.new_suffix_stmts_for_block.push(
|
||||
StmtConnect {
|
||||
lhs: Expr::canonical(output_wire),
|
||||
rhs: Expr::canonical(false.to_expr()),
|
||||
source_location,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
let tags_eq = match enum_type_state {
|
||||
EnumTypeState::TagEnumAndBody(_) => StructuralEq::with_flags(
|
||||
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_lhs).tag),
|
||||
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_rhs).tag),
|
||||
StructuralEqFlags {
|
||||
assume_padding_is_zeroed: true,
|
||||
},
|
||||
)
|
||||
.to_expr(),
|
||||
EnumTypeState::TagUIntAndBody(_) => {
|
||||
let lhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_lhs).tag;
|
||||
let rhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_rhs).tag;
|
||||
lhs.cmp_eq(rhs)
|
||||
}
|
||||
EnumTypeState::UInt(_) => {
|
||||
let lhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_lhs)
|
||||
[..unfolded_ty.discriminant_bit_width()];
|
||||
let rhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_rhs)
|
||||
[..unfolded_ty.discriminant_bit_width()];
|
||||
lhs_int_tag_expr.cmp_eq(rhs_int_tag_expr)
|
||||
}
|
||||
EnumTypeState::Unchanged => unreachable!(),
|
||||
};
|
||||
let mut match_arms = Vec::with_capacity(unfolded_ty.variants().len());
|
||||
for (variant_index, variant) in unfolded_ty.variants().iter().enumerate() {
|
||||
let block_scope = BlockScope::new(self, vec![], vec![]);
|
||||
let this = &mut *block_scope.state;
|
||||
let eq = if let Some(variant_ty) = variant.ty {
|
||||
let folded_lhs =
|
||||
this.handle_variant_access(unfolded_ty, folded_lhs, variant_index)?;
|
||||
let folded_rhs =
|
||||
this.handle_variant_access(unfolded_ty, folded_rhs, variant_index)?;
|
||||
this.handle_structural_eq(variant_ty, folded_lhs, folded_rhs, flags)?
|
||||
} else {
|
||||
true.to_expr()
|
||||
};
|
||||
match_arms.push(Block {
|
||||
memories: [].intern_slice(),
|
||||
stmts: this
|
||||
.new_prefix_stmts_for_block
|
||||
.drain(..)
|
||||
.chain([StmtConnect {
|
||||
lhs: Expr::canonical(output_wire),
|
||||
rhs: Expr::canonical(eq),
|
||||
source_location,
|
||||
}
|
||||
.into()])
|
||||
.chain(this.new_suffix_stmts_for_block.drain(..))
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
let match_stmt =
|
||||
self.handle_match(unfolded_ty, folded_lhs, source_location, &match_arms)?;
|
||||
self.new_suffix_stmts_for_block.push(
|
||||
StmtIf {
|
||||
cond: tags_eq,
|
||||
source_location,
|
||||
blocks: [
|
||||
Block {
|
||||
memories: [].intern_slice(),
|
||||
stmts: [match_stmt].intern_slice(),
|
||||
},
|
||||
Block {
|
||||
memories: [].intern_slice(),
|
||||
stmts: [].intern_slice(),
|
||||
},
|
||||
],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
Ok(output_wire)
|
||||
}
|
||||
fn handle_structural_eq(
|
||||
&mut self,
|
||||
unfolded_ty: CanonicalType,
|
||||
folded_lhs: Expr<CanonicalType>,
|
||||
folded_rhs: Expr<CanonicalType>,
|
||||
flags: StructuralEqFlags,
|
||||
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
||||
if !contains_any_enum_types(unfolded_ty) {
|
||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
||||
}
|
||||
match unfolded_ty {
|
||||
CanonicalType::Array(unfolded_ty) => {
|
||||
let unfolded_element_ty = unfolded_ty.element();
|
||||
let mut retval = None;
|
||||
for i in 0..unfolded_ty.len() {
|
||||
let element_eq = self.handle_structural_eq(
|
||||
unfolded_element_ty,
|
||||
ops::ArrayIndex::new(Expr::from_canonical(folded_lhs), i).to_expr(),
|
||||
ops::ArrayIndex::new(Expr::from_canonical(folded_rhs), i).to_expr(),
|
||||
flags,
|
||||
)?;
|
||||
retval = Some(match retval {
|
||||
Some(old_eq) => old_eq & element_eq,
|
||||
None => element_eq,
|
||||
});
|
||||
}
|
||||
Ok(retval.unwrap_or_else(|| {
|
||||
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
|
||||
}))
|
||||
}
|
||||
CanonicalType::Enum(unfolded_ty) => {
|
||||
self.handle_enum_structural_eq(unfolded_ty, folded_lhs, folded_rhs, flags)
|
||||
}
|
||||
CanonicalType::Bundle(unfolded_ty) => {
|
||||
let mut retval = None;
|
||||
for (i, field) in unfolded_ty.fields().iter().enumerate() {
|
||||
let field_eq = self.handle_structural_eq(
|
||||
field.ty,
|
||||
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_lhs), i)
|
||||
.to_expr(),
|
||||
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_rhs), i)
|
||||
.to_expr(),
|
||||
flags,
|
||||
)?;
|
||||
retval = Some(match retval {
|
||||
Some(old_eq) => old_eq & field_eq,
|
||||
None => field_eq,
|
||||
});
|
||||
}
|
||||
Ok(retval.unwrap_or_else(|| {
|
||||
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
|
||||
}))
|
||||
}
|
||||
CanonicalType::TraceAsString(unfolded_ty) => self.handle_structural_eq(
|
||||
unfolded_ty.inner_ty(),
|
||||
*Expr::<TraceAsString>::from_canonical(folded_lhs),
|
||||
*Expr::<TraceAsString>::from_canonical(folded_rhs),
|
||||
flags,
|
||||
),
|
||||
CanonicalType::UInt(_)
|
||||
| CanonicalType::SInt(_)
|
||||
| CanonicalType::Bool(_)
|
||||
| CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_)
|
||||
| CanonicalType::PhantomConst(_)
|
||||
| CanonicalType::DynSimOnly(_) => unreachable!("doesn't contain any enum types"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_port(
|
||||
|
|
@ -677,6 +891,7 @@ impl Folder for State {
|
|||
self.module_state_stack.push(ModuleState {
|
||||
module_name: v.name_id(),
|
||||
expr_cache: HashMap::default(),
|
||||
source_location: v.source_location(),
|
||||
});
|
||||
let retval = Fold::default_fold(v, self);
|
||||
self.module_state_stack.pop();
|
||||
|
|
@ -710,6 +925,18 @@ impl Folder for State {
|
|||
op.variant_index(),
|
||||
)?)
|
||||
}
|
||||
ExprEnum::StructuralEq(op) => {
|
||||
let ty = op.lhs().ty();
|
||||
assert_eq!(ty, op.rhs().ty());
|
||||
let folded_lhs = Expr::canonical(op.lhs()).fold(self)?;
|
||||
let folded_rhs = Expr::canonical(op.rhs()).fold(self)?;
|
||||
*Expr::expr_enum(self.handle_structural_eq(
|
||||
ty,
|
||||
folded_lhs,
|
||||
folded_rhs,
|
||||
op.flags(),
|
||||
)?)
|
||||
}
|
||||
ExprEnum::MemPort(mem_port) => {
|
||||
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
||||
ExprEnum::Wire(wire)
|
||||
|
|
@ -837,11 +1064,13 @@ impl Folder for State {
|
|||
}
|
||||
|
||||
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
|
||||
let block_scope = BlockScope::new(self, vec![], vec![]);
|
||||
let this = &mut *block_scope.state;
|
||||
let mut memories = vec![];
|
||||
let mut stmts = vec![];
|
||||
for memory in block.memories {
|
||||
let old_element_ty = memory.array_type().element();
|
||||
let new_element_ty = memory.array_type().element().fold(self)?;
|
||||
let new_element_ty = memory.array_type().element().fold(this)?;
|
||||
if new_element_ty != old_element_ty {
|
||||
let mut new_ports = vec![];
|
||||
for port in memory.ports() {
|
||||
|
|
@ -867,7 +1096,7 @@ impl Folder for State {
|
|||
continue;
|
||||
}
|
||||
let wire = Wire::new_unchecked(
|
||||
self.module_state_stack
|
||||
this.module_state_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.gen_name(&format!(
|
||||
|
|
@ -891,7 +1120,7 @@ impl Folder for State {
|
|||
Expr::canonical(wire.to_expr()),
|
||||
port.source_location(),
|
||||
);
|
||||
self.replacement_mem_ports.insert(port, wire.canonical());
|
||||
this.replacement_mem_ports.insert(port, wire.canonical());
|
||||
}
|
||||
memories.push(Mem::new_unchecked(
|
||||
memory.scoped_name(),
|
||||
|
|
@ -906,10 +1135,12 @@ impl Folder for State {
|
|||
memory.mem_annotations(),
|
||||
));
|
||||
} else {
|
||||
memories.push(memory.fold(self)?);
|
||||
memories.push(memory.fold(this)?);
|
||||
}
|
||||
}
|
||||
stmts.extend_from_slice(&block.stmts.fold(self)?);
|
||||
stmts.extend_from_slice(&block.stmts.fold(this)?);
|
||||
stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..));
|
||||
stmts.extend_from_slice(&this.new_suffix_stmts_for_block);
|
||||
Ok(Block {
|
||||
memories: Intern::intern_owned(memories),
|
||||
stmts: Intern::intern_owned(stmts),
|
||||
|
|
@ -1031,10 +1262,13 @@ pub fn simplify_enums(
|
|||
module: Interned<Module<Bundle>>,
|
||||
kind: SimplifyEnumsKind,
|
||||
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
||||
// TODO: deduce StructuralEq's assume_padding_is_zeroed
|
||||
module.fold(&mut State {
|
||||
enum_types: HashMap::default(),
|
||||
replacement_mem_ports: HashMap::default(),
|
||||
kind,
|
||||
module_state_stack: vec![],
|
||||
new_prefix_stmts_for_block: vec![],
|
||||
new_suffix_stmts_for_block: vec![],
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
||||
const TRY_STRUCTURAL_EQ: bool = true;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
|
|
|
|||
|
|
@ -3974,6 +3974,10 @@ impl Compiler {
|
|||
.compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg()))
|
||||
.map_ty(TraceAsString::from_canonical)
|
||||
.inner(),
|
||||
ExprEnum::StructuralEq(expr) => self.compile_expr(
|
||||
instantiated_module_or_global,
|
||||
Expr::canonical(expr.lhs().cast_to_bits().cmp_eq(expr.rhs().cast_to_bits())),
|
||||
),
|
||||
ExprEnum::ModuleIO(expr) => self
|
||||
.compile_value(TargetInInstantiatedModuleOrGlobal::from_target(
|
||||
instantiated_module_or_global,
|
||||
|
|
|
|||
|
|
@ -1508,6 +1508,8 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
|||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||
const TRY_STRUCTURAL_EQ: bool = false;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
|
|
@ -1527,6 +1529,8 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
|
|||
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
||||
for SimOnly<L>
|
||||
{
|
||||
const TRY_STRUCTURAL_EQ: bool = false;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
|
|
|
|||
|
|
@ -354,6 +354,39 @@ impl CanonicalType {
|
|||
}
|
||||
MyMemoize.get_owned((self, other))
|
||||
}
|
||||
pub fn contains_sim_only(self) -> bool {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct MyMemoize;
|
||||
impl Memoize for MyMemoize {
|
||||
type Input = CanonicalType;
|
||||
type InputOwned = CanonicalType;
|
||||
type Output = bool;
|
||||
|
||||
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||
match input {
|
||||
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
|
||||
false
|
||||
}
|
||||
CanonicalType::Array(ty) => ty.element().contains_sim_only(),
|
||||
CanonicalType::Enum(ty) => ty
|
||||
.variants()
|
||||
.iter()
|
||||
.any(|v| v.ty.is_some_and(CanonicalType::contains_sim_only)),
|
||||
CanonicalType::Bundle(ty) => {
|
||||
ty.fields().iter().any(|v| v.ty.contains_sim_only())
|
||||
}
|
||||
CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_)
|
||||
| CanonicalType::PhantomConst(_) => false,
|
||||
CanonicalType::DynSimOnly(_) => true,
|
||||
CanonicalType::TraceAsString(ty) => ty.inner_ty().contains_sim_only(),
|
||||
}
|
||||
}
|
||||
}
|
||||
MyMemoize.get_owned(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MatchVariantAndInactiveScope: Sized {
|
||||
|
|
@ -1882,6 +1915,8 @@ fn trace_as_string_cow_into_inner_value<T: Type>(
|
|||
}
|
||||
|
||||
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
||||
const TRY_STRUCTURAL_EQ: bool = <T as HdlPartialEqImpl<U>>::TRY_STRUCTURAL_EQ;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
|
|
|
|||
|
|
@ -709,44 +709,35 @@ circuit check_enum_cmp_eq:
|
|||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||
match lhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||
wire _cast_enum_to_bits_expr: UInt<10>
|
||||
match lhs:
|
||||
A:
|
||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||
B(_match_arm_value):
|
||||
skip
|
||||
C(_match_arm_value_1):
|
||||
skip
|
||||
B(_match_arm_value_2):
|
||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
skip
|
||||
B(_match_arm_value_3):
|
||||
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
|
||||
C(_match_arm_value_4):
|
||||
skip
|
||||
C(_match_arm_value_5):
|
||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
skip
|
||||
B(_match_arm_value_6):
|
||||
skip
|
||||
C(_match_arm_value_7):
|
||||
wire _array_literal_expr: UInt<1>[3]
|
||||
connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
|
||||
connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
|
||||
connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2])
|
||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||
wire _cast_to_bits_expr: UInt<3>
|
||||
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
|
||||
connect _cast_enum_to_bits_expr, UInt<10>(0)
|
||||
B(_cast_enum_to_bits_expr_B):
|
||||
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
|
||||
C(_cast_enum_to_bits_expr_C):
|
||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
|
||||
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
|
||||
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
|
||||
wire _cast_to_bits_expr: UInt<3>
|
||||
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
|
||||
wire _cast_enum_to_bits_expr_1: UInt<10>
|
||||
match rhs:
|
||||
A:
|
||||
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
|
||||
B(_cast_enum_to_bits_expr_B_1):
|
||||
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
|
||||
C(_cast_enum_to_bits_expr_C_1):
|
||||
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
|
||||
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
|
||||
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
|
||||
wire _cast_to_bits_expr_1: UInt<3>
|
||||
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
|
||||
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
|
||||
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1]
|
||||
",
|
||||
};
|
||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||
|
|
@ -764,60 +755,53 @@ circuit check_enum_cmp_eq:
|
|||
input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
|
||||
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||
match lhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||
wire _cast_enum_to_bits_expr: UInt<2>
|
||||
match lhs.tag:
|
||||
A:
|
||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||
B:
|
||||
skip
|
||||
C:
|
||||
skip
|
||||
connect _cast_enum_to_bits_expr, UInt<2>(0)
|
||||
B:
|
||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
skip
|
||||
B:
|
||||
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
||||
C:
|
||||
skip
|
||||
connect _cast_enum_to_bits_expr, UInt<2>(1)
|
||||
C:
|
||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||
A:
|
||||
skip
|
||||
B:
|
||||
skip
|
||||
C:
|
||||
wire _array_literal_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
||||
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])
|
||||
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])
|
||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||
wire _cast_to_bits_expr: UInt<3>
|
||||
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
|
||||
connect _cast_enum_to_bits_expr, UInt<2>(2)
|
||||
wire _cast_enum_to_bits_expr_1: UInt<2>
|
||||
match rhs.tag:
|
||||
A:
|
||||
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
|
||||
B:
|
||||
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
|
||||
C:
|
||||
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
|
||||
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
|
||||
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
|
||||
A:
|
||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||
B:
|
||||
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||
C:
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
wire _array_structural_eq: UInt<1>
|
||||
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
|
||||
wire _array_structural_eq_1: UInt<1>
|
||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||
",
|
||||
};
|
||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||
|
|
@ -834,51 +818,36 @@ circuit check_enum_cmp_eq:
|
|||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
||||
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else:
|
||||
wire _array_literal_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
||||
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])
|
||||
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])
|
||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||
wire _cast_to_bits_expr: UInt<3>
|
||||
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
|
||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
|
||||
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||
else:
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
wire _array_structural_eq: UInt<1>
|
||||
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
|
||||
wire _array_structural_eq_1: UInt<1>
|
||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||
",
|
||||
};
|
||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||
|
|
@ -894,51 +863,36 @@ circuit check_enum_cmp_eq:
|
|||
input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
|
||||
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||
skip
|
||||
else:
|
||||
wire _array_literal_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
||||
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])
|
||||
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])
|
||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||
wire _cast_to_bits_expr: UInt<3>
|
||||
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
|
||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||
connect __enum_structural_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||
else:
|
||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
|
||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
|
||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||
wire _array_structural_eq: UInt<1>
|
||||
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
|
||||
wire _array_structural_eq_1: UInt<1>
|
||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||
",
|
||||
};
|
||||
}
|
||||
|
|
@ -4931,12 +4885,14 @@ circuit check_struct_cmp_eq:
|
|||
wire _cast_to_bits_expr_1: UInt<3>
|
||||
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
|
||||
connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1]
|
||||
connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1]
|
||||
connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1]
|
||||
wire _bundle_structural_eq: UInt<1>
|
||||
connect _bundle_structural_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b))
|
||||
connect test_struct_cmp_eq, _bundle_structural_eq @[module-XXXXXXXXXX.rs 11:1]
|
||||
connect test_struct_cmp_ne, not(_bundle_structural_eq) @[module-XXXXXXXXXX.rs 13:1]
|
||||
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
|
||||
connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1]
|
||||
connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19:1]
|
||||
connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
|
||||
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
|
||||
connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1]
|
||||
",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
|||
note: required because it appears within the type `OpaqueSimValue`
|
||||
--> src/ty.rs
|
||||
|
|
||||
896 | pub struct OpaqueSimValue {
|
||||
929 | pub struct OpaqueSimValue {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `value::SimValueInner<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
@ -214,7 +214,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
|||
note: required because it appears within the type `OpaqueSimValue`
|
||||
--> src/ty.rs
|
||||
|
|
||||
896 | pub struct OpaqueSimValue {
|
||||
929 | pub struct OpaqueSimValue {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `value::SimValueInner<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
@ -326,7 +326,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
|||
note: required because it appears within the type `OpaqueSimValue`
|
||||
--> src/ty.rs
|
||||
|
|
||||
896 | pub struct OpaqueSimValue {
|
||||
929 | pub struct OpaqueSimValue {
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `value::SimValueInner<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
|
|||
|
|
@ -1055,6 +1055,15 @@
|
|||
"global()": "Visible"
|
||||
}
|
||||
},
|
||||
"ops::StructuralEq": {
|
||||
"data": {
|
||||
"$kind": "Struct",
|
||||
"$constructor": "ops::StructuralEq::with_flags",
|
||||
"lhs()": "Visible",
|
||||
"rhs()": "Visible",
|
||||
"flags()": "Opaque"
|
||||
}
|
||||
},
|
||||
"BlockId": {
|
||||
"data": {
|
||||
"$kind": "Opaque"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue