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_expr_ne = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
let mut fields_valueless_ne = vec![];
|
let mut fields_valueless_ne = vec![];
|
||||||
|
let mut fields_structural_eq = vec![];
|
||||||
for field in fields.named() {
|
for field in fields.named() {
|
||||||
let field_ident = field.ident();
|
let field_ident = field.ident();
|
||||||
let field_ty = field.ty();
|
let field_ty = field.ty();
|
||||||
|
|
@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#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=>
|
fields_value_eq.push(quote_spanned! {span=>
|
||||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#field_ident,
|
__lhs.#field_ident,
|
||||||
|
|
@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle {
|
||||||
let expr_ne_body;
|
let expr_ne_body;
|
||||||
let valueless_eq_body;
|
let valueless_eq_body;
|
||||||
let valueless_ne_body;
|
let valueless_ne_body;
|
||||||
|
let structural_eq;
|
||||||
if fields_len == 0 {
|
if fields_len == 0 {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
true
|
true
|
||||||
|
|
@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle {
|
||||||
valueless_ne_body = quote_spanned! {span=>
|
valueless_ne_body = quote_spanned! {span=>
|
||||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||||
};
|
};
|
||||||
|
structural_eq = quote_spanned! {span=>
|
||||||
|
true
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
#(#fields_value_eq)&*
|
#(#fields_value_eq)&*
|
||||||
|
|
@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle {
|
||||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||||
#(#fields_valueless_ne)|*
|
#(#fields_valueless_ne)|*
|
||||||
};
|
};
|
||||||
|
structural_eq = quote_spanned! {span=>
|
||||||
|
#(#fields_structural_eq)&&*
|
||||||
|
};
|
||||||
};
|
};
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__lhs: Self,
|
||||||
|
|
@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::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
|
#expr_eq_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::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
|
#expr_ne_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum {
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
#[allow(non_snake_case, dead_code)]
|
#[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(
|
::fayalite::sim::value::SimValue::from_value(
|
||||||
#self_token.#sim_builder_ty_field_ident,
|
#self_token.#sim_builder_ty_field_ident,
|
||||||
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
#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
|
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
fn fmt(
|
||||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
|
&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);
|
}.to_tokens(tokens);
|
||||||
|
|
@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum {
|
||||||
let mut variants_value_eq = vec![];
|
let mut variants_value_eq = vec![];
|
||||||
let mut variants_expr_eq = vec![];
|
let mut variants_expr_eq = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
|
let mut structural_eq: Option<TokenStream> = None;
|
||||||
for (
|
for (
|
||||||
variant_index,
|
variant_index,
|
||||||
ParsedVariant {
|
ParsedVariant {
|
||||||
|
|
@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#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=>
|
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(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#variant_ident,
|
__lhs.#variant_ident,
|
||||||
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
||||||
|
|
@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum {
|
||||||
else {
|
else {
|
||||||
::fayalite::__std::unreachable!();
|
::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=>
|
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 {
|
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||||
variants_value_eq.push(quote_spanned! {span=>
|
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
|
__lhs_unknown == __rhs_unknown
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
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=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__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: 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 {
|
) -> ::fayalite::__std::primitive::bool {
|
||||||
match (&*__lhs_value, &*__rhs_value) {
|
match (&*__lhs_value, &*__rhs_value) {
|
||||||
#(#variants_value_eq)*
|
#(#variants_value_eq)*
|
||||||
|
|
@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::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);
|
::fayalite::module::connect(__retval, false);
|
||||||
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
||||||
#(#variants_expr_eq)*
|
#(#variants_expr_eq)*
|
||||||
|
|
@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimValue = #sim_value_ident #type_generics;
|
type SimValue = #sim_value_ident #type_generics;
|
||||||
type MatchVariant = #match_variant_ident #type_generics;
|
type MatchVariant = #match_variant_ident #type_generics;
|
||||||
type MatchActiveScope = ::fayalite::module::Scope;
|
type MatchActiveScope = ::fayalite::module::Scope;
|
||||||
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
type MatchVariantAndInactiveScope =
|
||||||
|
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||||
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
||||||
|
|
||||||
fn match_variants(
|
fn match_variants(
|
||||||
|
|
@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::int::Bool
|
::fayalite::int::Bool
|
||||||
}
|
}
|
||||||
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
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]
|
#[track_caller]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::__std::panic!("expected enum");
|
::fayalite::__std::panic!("expected enum");
|
||||||
};
|
};
|
||||||
let #variants_token = ::fayalite::enum_::EnumType::variants(&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 {
|
Self {
|
||||||
#(#from_canonical_body_fields)*
|
#(#from_canonical_body_fields)*
|
||||||
}
|
}
|
||||||
|
|
@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimBuilder = #sim_builder_ident #type_generics;
|
type SimBuilder = #sim_builder_ident #type_generics;
|
||||||
fn match_activate_scope(
|
fn match_activate_scope(
|
||||||
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
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();
|
let (#variant_access_token, scope) = v.activate();
|
||||||
(
|
(
|
||||||
match #variant_access_token.variant_index() {
|
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
|
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#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)
|
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum {
|
||||||
&self,
|
&self,
|
||||||
ty: #target #type_generics,
|
ty: #target #type_generics,
|
||||||
) -> ::fayalite::sim::value::SimValue<#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(
|
fn into_sim_value_with_type(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,8 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
|
||||||
where
|
where
|
||||||
Lhs: HdlPartialEqImpl<Rhs>,
|
Lhs: HdlPartialEqImpl<Rhs>,
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::TRY_STRUCTURAL_EQ;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
|
||||||
|
|
@ -708,6 +708,8 @@ macro_rules! impl_tuples {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
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]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ expr_enum! {
|
||||||
CastBitsTo(ops::CastBitsTo),
|
CastBitsTo(ops::CastBitsTo),
|
||||||
ToTraceAsString(ops::ToTraceAsString),
|
ToTraceAsString(ops::ToTraceAsString),
|
||||||
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
||||||
|
StructuralEq(ops::StructuralEq),
|
||||||
ModuleIO(ModuleIO<CanonicalType>),
|
ModuleIO(ModuleIO<CanonicalType>),
|
||||||
Instance(Instance<Bundle>),
|
Instance(Instance<Bundle>),
|
||||||
Wire(Wire<CanonicalType>),
|
Wire(Wire<CanonicalType>),
|
||||||
|
|
@ -701,6 +702,7 @@ macro_rules! impl_hdl_cmp {
|
||||||
impl_helper = $HdlCmpImplHelper:ident,
|
impl_helper = $HdlCmpImplHelper:ident,
|
||||||
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
||||||
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
||||||
|
$(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)?
|
||||||
]
|
]
|
||||||
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
||||||
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
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>)? {
|
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
||||||
|
$(const $TRY_STRUCTURAL_EQ: bool;)?
|
||||||
|
|
||||||
$(#[track_caller]
|
$(#[track_caller]
|
||||||
fn $cmp_value_fn(
|
fn $cmp_value_fn(
|
||||||
$cmp_value_lhs: Self,
|
$cmp_value_lhs: Self,
|
||||||
|
|
@ -912,6 +916,7 @@ impl_hdl_cmp! {
|
||||||
#[
|
#[
|
||||||
impl_helper = HdlPartialEqImplHelper,
|
impl_helper = HdlPartialEqImplHelper,
|
||||||
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
||||||
|
try_structural_eq = TRY_STRUCTURAL_EQ,
|
||||||
]
|
]
|
||||||
pub trait HdlPartialEq<Rhs: ValueType>:
|
pub trait HdlPartialEq<Rhs: ValueType>:
|
||||||
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
||||||
UIntType, UIntValue,
|
UIntType, UIntValue,
|
||||||
},
|
},
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned, MemoizeGeneric},
|
||||||
phantom_const::{PhantomConst, PhantomConstValue},
|
phantom_const::{PhantomConst, PhantomConstValue},
|
||||||
reset::{
|
reset::{
|
||||||
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
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_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)]
|
#[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)]
|
#[type($Lhs:ty, $Rhs:ty)]
|
||||||
|
$(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])?
|
||||||
#[trait($Trait:ident)]
|
#[trait($Trait:ident)]
|
||||||
$(
|
$(
|
||||||
struct $name:ident;
|
struct $name:ident;
|
||||||
|
|
@ -3045,6 +3046,7 @@ macro_rules! impl_compare_op {
|
||||||
})*
|
})*
|
||||||
|
|
||||||
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
||||||
|
$(const $TRY_STRUCTURAL_EQ: bool = true;)?
|
||||||
$(fn $value_method(
|
$(fn $value_method(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
||||||
|
|
@ -3065,6 +3067,7 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
||||||
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
||||||
#[type(Bool, Bool)]
|
#[type(Bool, Bool)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
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_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())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
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_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())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
||||||
|
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
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 {
|
macro_rules! impl_compare_forwards_to_bool {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl HdlPartialEqImpl<Self> for $ty {
|
impl HdlPartialEqImpl<Self> for $ty {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_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},
|
bundle::{BundleField, BundleType},
|
||||||
enum_::{EnumType, EnumVariant},
|
enum_::{EnumType, EnumVariant},
|
||||||
expr::{
|
expr::{
|
||||||
ExprEnum,
|
CastToImpl, ExprEnum,
|
||||||
ops::{self, VariantAccess},
|
ops::{self, VariantAccess},
|
||||||
target::{
|
target::{
|
||||||
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
||||||
|
|
@ -389,6 +389,7 @@ struct BlockDefinitionsCache {
|
||||||
cast_bits_to_array_exprs: RefCell<HashMap<(String, Array), String>>,
|
cast_bits_to_array_exprs: RefCell<HashMap<(String, Array), String>>,
|
||||||
cast_bits_to_phantom_const_exprs: RefCell<HashMap<(String, PhantomConst), String>>,
|
cast_bits_to_phantom_const_exprs: RefCell<HashMap<(String, PhantomConst), String>>,
|
||||||
per_module_formal_inputs: RefCell<HashMap<(FormalInput, bool), String>>,
|
per_module_formal_inputs: RefCell<HashMap<(FormalInput, bool), String>>,
|
||||||
|
structural_eq_exprs: RefCell<HashMap<(String, String), String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockDefinitions<'a> {
|
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(
|
fn expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: Expr<CanonicalType>,
|
expr: Expr<CanonicalType>,
|
||||||
|
|
@ -2117,6 +2255,13 @@ endmodule
|
||||||
ExprEnum::TraceAsStringAsInner(expr) => {
|
ExprEnum::TraceAsStringAsInner(expr) => {
|
||||||
self.expr(Expr::canonical(expr.arg()), definitions, const_ty)
|
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::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()),
|
||||||
ExprEnum::Instance(expr) => {
|
ExprEnum::Instance(expr) => {
|
||||||
assert!(!const_ty, "not a constant");
|
assert!(!const_ty, "not a constant");
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,8 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type {
|
||||||
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
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>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
||||||
for $UIntInRangeType<Start, End>
|
for $UIntInRangeType<Start, End>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
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>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
||||||
for UIntType<Width>
|
for UIntType<Width>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
|
||||||
|
|
@ -2206,6 +2206,7 @@ impl transform::visit::Visitor for AssertExprValidity<'_> {
|
||||||
| ExprEnum::CastBitsTo(_)
|
| ExprEnum::CastBitsTo(_)
|
||||||
| ExprEnum::ToTraceAsString(_)
|
| ExprEnum::ToTraceAsString(_)
|
||||||
| ExprEnum::TraceAsStringAsInner(_)
|
| ExprEnum::TraceAsStringAsInner(_)
|
||||||
|
| ExprEnum::StructuralEq(_)
|
||||||
| ExprEnum::FormalInput(_) => v.default_visit(self),
|
| ExprEnum::FormalInput(_) => v.default_visit(self),
|
||||||
ExprEnum::VariantAccess(_)
|
ExprEnum::VariantAccess(_)
|
||||||
| ExprEnum::ModuleIO(_)
|
| ExprEnum::ModuleIO(_)
|
||||||
|
|
|
||||||
|
|
@ -1208,6 +1208,7 @@ impl<P: Pass> RunPass<P> for ExprEnum {
|
||||||
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
||||||
}
|
}
|
||||||
ExprEnum::ToTraceAsString(expr) => 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::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
ExprEnum::Instance(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)),
|
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> {
|
impl RunPassExpr for ModuleIO<CanonicalType> {
|
||||||
type Args<'a> = [Expr<CanonicalType>; 0];
|
type Args<'a> = [Expr<CanonicalType>; 0];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{
|
use crate::{
|
||||||
array::{Array, ArrayType},
|
bundle::{BundleField, BundleType},
|
||||||
bundle::{Bundle, BundleField, BundleType},
|
enum_::{EnumType, EnumVariant},
|
||||||
enum_::{Enum, EnumType, EnumVariant},
|
|
||||||
expr::{
|
expr::{
|
||||||
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
|
ExprEnum,
|
||||||
ops::{self, EnumLiteral},
|
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
|
||||||
},
|
},
|
||||||
hdl,
|
|
||||||
int::UInt,
|
|
||||||
intern::{Intern, InternSlice, Interned, Memoize},
|
intern::{Intern, InternSlice, Interned, Memoize},
|
||||||
memory::{DynPortType, Mem, MemPort},
|
memory::{DynPortType, MemPort},
|
||||||
module::{
|
module::{
|
||||||
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
||||||
transform::visit::{Fold, Folder},
|
transform::visit::{Fold, Folder},
|
||||||
},
|
},
|
||||||
source_location::SourceLocation,
|
prelude::*,
|
||||||
ty::{CanonicalType, TraceAsString, Type},
|
|
||||||
util::HashMap,
|
util::HashMap,
|
||||||
wire::Wire,
|
|
||||||
};
|
};
|
||||||
use core::fmt;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SimplifyEnumsError {
|
pub enum SimplifyEnumsError {
|
||||||
|
|
@ -97,6 +92,7 @@ enum EnumTypeState {
|
||||||
struct ModuleState {
|
struct ModuleState {
|
||||||
module_name: NameId,
|
module_name: NameId,
|
||||||
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
||||||
|
source_location: SourceLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleState {
|
impl ModuleState {
|
||||||
|
|
@ -110,6 +106,45 @@ struct State {
|
||||||
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
module_state_stack: Vec<ModuleState>,
|
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 {
|
impl State {
|
||||||
|
|
@ -549,6 +584,185 @@ impl State {
|
||||||
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
| 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(
|
fn connect_port(
|
||||||
|
|
@ -677,6 +891,7 @@ impl Folder for State {
|
||||||
self.module_state_stack.push(ModuleState {
|
self.module_state_stack.push(ModuleState {
|
||||||
module_name: v.name_id(),
|
module_name: v.name_id(),
|
||||||
expr_cache: HashMap::default(),
|
expr_cache: HashMap::default(),
|
||||||
|
source_location: v.source_location(),
|
||||||
});
|
});
|
||||||
let retval = Fold::default_fold(v, self);
|
let retval = Fold::default_fold(v, self);
|
||||||
self.module_state_stack.pop();
|
self.module_state_stack.pop();
|
||||||
|
|
@ -710,6 +925,18 @@ impl Folder for State {
|
||||||
op.variant_index(),
|
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) => {
|
ExprEnum::MemPort(mem_port) => {
|
||||||
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
||||||
ExprEnum::Wire(wire)
|
ExprEnum::Wire(wire)
|
||||||
|
|
@ -837,11 +1064,13 @@ impl Folder for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
|
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 memories = vec![];
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
for memory in block.memories {
|
for memory in block.memories {
|
||||||
let old_element_ty = memory.array_type().element();
|
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 {
|
if new_element_ty != old_element_ty {
|
||||||
let mut new_ports = vec![];
|
let mut new_ports = vec![];
|
||||||
for port in memory.ports() {
|
for port in memory.ports() {
|
||||||
|
|
@ -867,7 +1096,7 @@ impl Folder for State {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let wire = Wire::new_unchecked(
|
let wire = Wire::new_unchecked(
|
||||||
self.module_state_stack
|
this.module_state_stack
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.gen_name(&format!(
|
.gen_name(&format!(
|
||||||
|
|
@ -891,7 +1120,7 @@ impl Folder for State {
|
||||||
Expr::canonical(wire.to_expr()),
|
Expr::canonical(wire.to_expr()),
|
||||||
port.source_location(),
|
port.source_location(),
|
||||||
);
|
);
|
||||||
self.replacement_mem_ports.insert(port, wire.canonical());
|
this.replacement_mem_ports.insert(port, wire.canonical());
|
||||||
}
|
}
|
||||||
memories.push(Mem::new_unchecked(
|
memories.push(Mem::new_unchecked(
|
||||||
memory.scoped_name(),
|
memory.scoped_name(),
|
||||||
|
|
@ -906,10 +1135,12 @@ impl Folder for State {
|
||||||
memory.mem_annotations(),
|
memory.mem_annotations(),
|
||||||
));
|
));
|
||||||
} else {
|
} 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 {
|
Ok(Block {
|
||||||
memories: Intern::intern_owned(memories),
|
memories: Intern::intern_owned(memories),
|
||||||
stmts: Intern::intern_owned(stmts),
|
stmts: Intern::intern_owned(stmts),
|
||||||
|
|
@ -1031,10 +1262,13 @@ pub fn simplify_enums(
|
||||||
module: Interned<Module<Bundle>>,
|
module: Interned<Module<Bundle>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
||||||
|
// TODO: deduce StructuralEq's assume_padding_is_zeroed
|
||||||
module.fold(&mut State {
|
module.fold(&mut State {
|
||||||
enum_types: HashMap::default(),
|
enum_types: HashMap::default(),
|
||||||
replacement_mem_ports: HashMap::default(),
|
replacement_mem_ports: HashMap::default(),
|
||||||
kind,
|
kind,
|
||||||
module_state_stack: vec![],
|
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> {
|
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = true;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -3974,6 +3974,10 @@ impl Compiler {
|
||||||
.compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg()))
|
.compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg()))
|
||||||
.map_ty(TraceAsString::from_canonical)
|
.map_ty(TraceAsString::from_canonical)
|
||||||
.inner(),
|
.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
|
ExprEnum::ModuleIO(expr) => self
|
||||||
.compile_value(TargetInInstantiatedModuleOrGlobal::from_target(
|
.compile_value(TargetInInstantiatedModuleOrGlobal::from_target(
|
||||||
instantiated_module_or_global,
|
instantiated_module_or_global,
|
||||||
|
|
|
||||||
|
|
@ -1508,6 +1508,8 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -1527,6 +1529,8 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
||||||
for SimOnly<L>
|
for SimOnly<L>
|
||||||
{
|
{
|
||||||
|
const TRY_STRUCTURAL_EQ: bool = false;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,39 @@ impl CanonicalType {
|
||||||
}
|
}
|
||||||
MyMemoize.get_owned((self, other))
|
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 {
|
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> {
|
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]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -709,44 +709,35 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_enum_to_bits_expr: UInt<10>
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
match lhs:
|
||||||
match lhs: @[module-XXXXXXXXXX.rs 5:1]
|
|
||||||
A:
|
A:
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<10>(0)
|
||||||
A:
|
B(_cast_enum_to_bits_expr_B):
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
|
||||||
B(_match_arm_value):
|
C(_cast_enum_to_bits_expr_C):
|
||||||
skip
|
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||||
C(_match_arm_value_1):
|
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
|
||||||
skip
|
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
|
||||||
B(_match_arm_value_2):
|
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_to_bits_expr: UInt<3>
|
||||||
A:
|
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]))
|
||||||
skip
|
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
|
||||||
B(_match_arm_value_3):
|
wire _cast_enum_to_bits_expr_1: UInt<10>
|
||||||
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
|
match rhs:
|
||||||
C(_match_arm_value_4):
|
A:
|
||||||
skip
|
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
|
||||||
C(_match_arm_value_5):
|
B(_cast_enum_to_bits_expr_B_1):
|
||||||
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
|
||||||
A:
|
C(_cast_enum_to_bits_expr_C_1):
|
||||||
skip
|
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
||||||
B(_match_arm_value_6):
|
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
|
||||||
skip
|
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
|
||||||
C(_match_arm_value_7):
|
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_to_bits_expr_1: UInt<3>
|
||||||
connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
|
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 _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
|
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
|
||||||
connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2])
|
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[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 lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
match lhs.tag: @[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:
|
A:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(0)
|
||||||
A:
|
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
|
||||||
B:
|
|
||||||
skip
|
|
||||||
C:
|
|
||||||
skip
|
|
||||||
B:
|
B:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(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
|
|
||||||
C:
|
C:
|
||||||
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_enum_to_bits_expr, UInt<2>(2)
|
||||||
A:
|
wire _cast_enum_to_bits_expr_1: UInt<2>
|
||||||
skip
|
match rhs.tag:
|
||||||
B:
|
A:
|
||||||
skip
|
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
|
||||||
C:
|
B:
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
C:
|
||||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
|
||||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
A:
|
||||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
B:
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
C:
|
||||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 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], _cast_bits_to_array_expr_flattened[1]
|
||||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||||
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||||
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||||
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||||
wire _cast_to_bits_expr: UInt<3>
|
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||||
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_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
|
wire _array_structural_eq: UInt<1>
|
||||||
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6: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
|
#[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 lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
skip
|
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
else:
|
||||||
skip
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||||
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
else:
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened: 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_flattened[0], bits(bits(lhs.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[0], _cast_bits_to_array_expr_flattened[0]
|
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.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[1], _cast_bits_to_array_expr_flattened[1]
|
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
wire _array_structural_eq: UInt<1>
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
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 _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _array_structural_eq_1: UInt<1>
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[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 lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
||||||
skip
|
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
||||||
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5: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]
|
||||||
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
else:
|
||||||
skip
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
|
||||||
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
skip
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
||||||
else:
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
wire _array_literal_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened: 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_flattened[0], bits(bits(bits(lhs, 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[0], _cast_bits_to_array_expr_flattened[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_flattened[1], bits(bits(bits(lhs, 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[1], _cast_bits_to_array_expr_flattened[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_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
wire _array_structural_eq: UInt<1>
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
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 _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _array_structural_eq_1: UInt<1>
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
||||||
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]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -4931,12 +4885,14 @@ circuit check_struct_cmp_eq:
|
||||||
wire _cast_to_bits_expr_1: UInt<3>
|
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_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 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]
|
wire _bundle_structural_eq: UInt<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]
|
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_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_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`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> 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`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> 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`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
896 | pub struct OpaqueSimValue {
|
929 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
|
||||||
|
|
@ -1055,6 +1055,15 @@
|
||||||
"global()": "Visible"
|
"global()": "Visible"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ops::StructuralEq": {
|
||||||
|
"data": {
|
||||||
|
"$kind": "Struct",
|
||||||
|
"$constructor": "ops::StructuralEq::with_flags",
|
||||||
|
"lhs()": "Visible",
|
||||||
|
"rhs()": "Visible",
|
||||||
|
"flags()": "Opaque"
|
||||||
|
}
|
||||||
|
},
|
||||||
"BlockId": {
|
"BlockId": {
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Opaque"
|
"$kind": "Opaque"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue