diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index f7ad68d..451bc7e 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -1133,6 +1133,7 @@ impl ToTokens for ParsedBundle { let mut fields_expr_ne = vec![]; let mut fields_valueless_eq = vec![]; let mut fields_valueless_ne = vec![]; + let mut fields_structural_eq = vec![]; for field in fields.named() { let field_ident = field.ident(); let field_ty = field.ty(); @@ -1141,6 +1142,9 @@ impl ToTokens for ParsedBundle { .push(parse_quote_spanned! {cmp_eq.span=> #field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty> }); + fields_structural_eq.push(quote_spanned! {cmp_eq.span=> + <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ + }); fields_value_eq.push(quote_spanned! {span=> ::fayalite::expr::HdlPartialEqImpl::cmp_value_eq( __lhs.#field_ident, @@ -1188,6 +1192,7 @@ impl ToTokens for ParsedBundle { let expr_ne_body; let valueless_eq_body; let valueless_ne_body; + let structural_eq; if fields_len == 0 { value_eq_body = quote_spanned! {span=> true @@ -1207,6 +1212,9 @@ impl ToTokens for ParsedBundle { valueless_ne_body = quote_spanned! {span=> ::fayalite::expr::Valueless::new(::fayalite::int::Bool) }; + structural_eq = quote_spanned! {span=> + true + }; } else { value_eq_body = quote_spanned! {span=> #(#fields_value_eq)&* @@ -1230,12 +1238,17 @@ impl ToTokens for ParsedBundle { let __rhs = ::fayalite::expr::ValueType::ty(&__rhs); #(#fields_valueless_ne)|* }; + structural_eq = quote_spanned! {span=> + #(#fields_structural_eq)&&* + }; }; quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::expr::HdlPartialEqImpl for #target #type_generics #cmp_eq_where_clause { + const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq; + #[track_caller] fn cmp_value_eq( __lhs: Self, @@ -1261,6 +1274,16 @@ impl ToTokens for ParsedBundle { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { + if >::TRY_STRUCTURAL_EQ { + if let ::fayalite::__std::result::Result::Ok(__retval) = + ::fayalite::expr::ops::StructuralEq::try_new( + ::fayalite::expr::Expr::canonical(__lhs), + ::fayalite::expr::Expr::canonical(__rhs), + ) + { + return ::fayalite::expr::ToExpr::to_expr(&__retval); + } + } #expr_eq_body } @@ -1269,6 +1292,14 @@ impl ToTokens for ParsedBundle { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { + if >::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 } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index e9f013b..68fcc02 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -643,7 +643,9 @@ impl ToTokens for ParsedEnum { #where_clause { #[allow(non_snake_case, dead_code)] - #vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> { + #vis fn #ident( + #self_token, + ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { ::fayalite::sim::value::SimValue::from_value( #self_token.#sim_builder_ty_field_ident, #sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()), @@ -929,8 +931,14 @@ impl ToTokens for ParsedEnum { impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics #where_clause { - fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result { - <#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f) + fn fmt( + &self, + f: &mut ::fayalite::__std::fmt::Formatter<'_>, + ) -> ::fayalite::__std::fmt::Result { + <#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display( + self, + f, + ) } } }.to_tokens(tokens); @@ -946,6 +954,7 @@ impl ToTokens for ParsedEnum { let mut variants_value_eq = vec![]; let mut variants_expr_eq = vec![]; let mut fields_valueless_eq = vec![]; + let mut structural_eq: Option = None; for ( variant_index, ParsedVariant { @@ -971,8 +980,23 @@ impl ToTokens for ParsedEnum { .push(parse_quote_spanned! {cmp_eq.span=> #field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty> }); + match &mut structural_eq { + Some(structural_eq) => { + structural_eq.extend(quote_spanned! {cmp_eq.span=> + && <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ + }); + } + None => { + structural_eq = Some(quote_spanned! {cmp_eq.span=> + <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ + }); + } + } variants_value_eq.push(quote_spanned! {span=> - (#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => { + ( + #sim_value_ident::#variant_ident(__lhs_field, _), + #sim_value_ident::#variant_ident(__rhs_field, _), + ) => { ::fayalite::expr::HdlPartialEqImpl::cmp_value_eq( __lhs.#variant_ident, ::fayalite::__std::borrow::Cow::Borrowed(__lhs_field), @@ -1002,7 +1026,10 @@ impl ToTokens for ParsedEnum { else { ::fayalite::__std::unreachable!(); }; - ::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs)); + ::fayalite::module::connect( + __retval, + ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs), + ); } }); fields_valueless_eq.push(quote_spanned! {span=> @@ -1043,7 +1070,10 @@ impl ToTokens for ParsedEnum { } if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { variants_value_eq.push(quote_spanned! {span=> - (#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => { + ( + #sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), + #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown), + ) => { __lhs_unknown == __rhs_unknown } }); @@ -1060,17 +1090,26 @@ impl ToTokens for ParsedEnum { } }; let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq"); + let structural_eq = structural_eq.unwrap_or_else(|| { + quote_spanned! {span=> + true + } + }); quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::expr::HdlPartialEqImpl for #target #type_generics #cmp_eq_where_clause { + const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq; + #[track_caller] fn cmp_value_eq( __lhs: Self, - __lhs_value: ::fayalite::__std::borrow::Cow<'_, ::SimValue>, + __lhs_value: ::fayalite::__std::borrow::Cow<'_, + ::SimValue>, __rhs: Self, - __rhs_value: ::fayalite::__std::borrow::Cow<'_, ::SimValue>, + __rhs_value: ::fayalite::__std::borrow::Cow<'_, + ::SimValue>, ) -> ::fayalite::__std::primitive::bool { match (&*__lhs_value, &*__rhs_value) { #(#variants_value_eq)* @@ -1083,7 +1122,20 @@ impl ToTokens for ParsedEnum { __lhs: ::fayalite::expr::Expr, __rhs: ::fayalite::expr::Expr, ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool); + if >::TRY_STRUCTURAL_EQ { + if let ::fayalite::__std::result::Result::Ok(__retval) = + ::fayalite::expr::ops::StructuralEq::try_new( + ::fayalite::expr::Expr::canonical(__lhs), + ::fayalite::expr::Expr::canonical(__rhs), + ) + { + return ::fayalite::expr::ToExpr::to_expr(&__retval); + } + } + let __retval = ::fayalite::module::wire( + ::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), + ::fayalite::int::Bool, + ); ::fayalite::module::connect(__retval, false); let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs); #(#variants_expr_eq)* @@ -1112,7 +1164,8 @@ impl ToTokens for ParsedEnum { type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = ::fayalite::module::Scope; - type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope; + type MatchVariantAndInactiveScope = + ::fayalite::enum_::EnumMatchVariantAndInactiveScope; type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter; fn match_variants( @@ -1125,7 +1178,9 @@ impl ToTokens for ParsedEnum { ::fayalite::int::Bool } fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token))) + ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new( + ::fayalite::enum_::EnumType::variants(#self_token), + )) } #[track_caller] #[allow(non_snake_case)] @@ -1134,7 +1189,11 @@ impl ToTokens for ParsedEnum { ::fayalite::__std::panic!("expected enum"); }; let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_); - ::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants"); + ::fayalite::__std::assert_eq!( + #variants_token.len(), + #variants_len, + "enum has wrong number of variants", + ); Self { #(#from_canonical_body_fields)* } @@ -1180,7 +1239,10 @@ impl ToTokens for ParsedEnum { type SimBuilder = #sim_builder_ident #type_generics; fn match_activate_scope( v: ::MatchVariantAndInactiveScope, - ) -> (::MatchVariant, ::MatchActiveScope) { + ) -> ( + ::MatchVariant, + ::MatchActiveScope, + ) { let (#variant_access_token, scope) = v.activate(); ( match #variant_access_token.variant_index() { @@ -1200,7 +1262,10 @@ impl ToTokens for ParsedEnum { impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics #where_clause { - fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result { + fn fmt( + &self, + f: &mut ::fayalite::__std::fmt::Formatter<'_>, + ) -> ::fayalite::__std::fmt::Result { <#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f) } } @@ -1213,7 +1278,10 @@ impl ToTokens for ParsedEnum { &self, ty: #target #type_generics, ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) + ::fayalite::sim::value::SimValue::from_value( + ty, + ::fayalite::__std::clone::Clone::clone(self), + ) } fn into_sim_value_with_type( self, diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index fa754fd..95ecb8b 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -4,7 +4,7 @@ use crate::{ expr::{ CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless, - ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator}, + ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, StructuralEq}, }, int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType}, intern::{Intern, Interned, LazyInterned}, @@ -367,6 +367,8 @@ impl HdlPartialEqImpl> for where Lhs: HdlPartialEqImpl, { + const TRY_STRUCTURAL_EQ: bool = >::TRY_STRUCTURAL_EQ; + fn cmp_value_eq( lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -387,6 +389,11 @@ where } fn cmp_expr_eq(lhs: Expr, rhs: Expr>) -> Expr { assert_eq!(lhs.ty().len(), rhs.ty().len()); + if Self::TRY_STRUCTURAL_EQ { + if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) { + return retval.to_expr(); + } + } lhs.into_iter() .zip(rhs) .map(|(l, r)| l.cmp_eq(r)) @@ -396,6 +403,11 @@ where } fn cmp_expr_ne(lhs: Expr, rhs: Expr>) -> Expr { assert_eq!(lhs.ty().len(), rhs.ty().len()); + if Self::TRY_STRUCTURAL_EQ { + if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) { + return !retval.to_expr(); + } + } lhs.into_iter() .zip(rhs) .map(|(l, r)| l.cmp_ne(r)) diff --git a/crates/fayalite/src/build/graph.rs b/crates/fayalite/src/build/graph.rs index bed8829..e46f0a4 100644 --- a/crates/fayalite/src/build/graph.rs +++ b/crates/fayalite/src/build/graph.rs @@ -12,7 +12,7 @@ use crate::{ use eyre::{ContextCompat, eyre}; use petgraph::{ algo::{DfsSpace, kosaraju_scc, toposort}, - graph::DiGraph, + graph::{DiGraph, NodeIndex}, visit::{GraphBase, Visitable}, }; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq}; @@ -465,7 +465,7 @@ impl JobGraph { } }) .expect("we know there's a cycle"); - let cycle_set = HashSet::from_iter(cycle.iter().copied()); + let cycle_set = HashSet::::from_iter(cycle.iter().copied()); let job = cycle .into_iter() .find_map(|node_id| { @@ -701,7 +701,7 @@ impl JobGraph { job: DynJob, thread: ScopedJoinHandle<'scope, eyre::Result>>, } - let mut running_jobs = HashMap::default(); + let mut running_jobs = HashMap::::default(); let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel(); let mut next_finished_job = None; loop { diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 5fad35c..5a97944 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -5,7 +5,7 @@ use crate::{ expr::{ CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType, Valueless, - ops::{ArrayLiteral, BundleLiteral}, + ops::{ArrayLiteral, BundleLiteral, StructuralEq}, value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue}, }, int::{Bool, DynSize}, @@ -708,6 +708,8 @@ macro_rules! impl_tuples { } } impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) { + const TRY_STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::TRY_STRUCTURAL_EQ)*; + #[track_caller] fn cmp_value_eq( lhs: Self, @@ -725,6 +727,11 @@ macro_rules! impl_tuples { #[track_caller] fn cmp_expr_eq(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { + if Self::TRY_STRUCTURAL_EQ { + if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) { + return retval.to_expr(); + } + } let ($($lhs_var,)*) = *lhs; let ($($rhs_var,)*) = *rhs; ArrayLiteral::::new( @@ -737,6 +744,11 @@ macro_rules! impl_tuples { #[track_caller] fn cmp_expr_ne(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { + if Self::TRY_STRUCTURAL_EQ { + if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) { + return !retval.to_expr(); + } + } let ($($lhs_var,)*) = *lhs; let ($($rhs_var,)*) = *rhs; ArrayLiteral::::new( diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index eb4bf0f..f9f239f 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -221,6 +221,7 @@ expr_enum! { CastBitsTo(ops::CastBitsTo), ToTraceAsString(ops::ToTraceAsString), TraceAsStringAsInner(ops::TraceAsStringAsInner), + StructuralEq(ops::StructuralEq), ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), @@ -701,6 +702,7 @@ macro_rules! impl_hdl_cmp { impl_helper = $HdlCmpImplHelper:ident, $(impl_helper_base = $HdlCmpImplHelperBase:ident,)? impl_helper_sealed = $HdlCmpImplHelperSealed:ident, + $(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)? ] $vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>: ValueType $(+ $HdlCmpImplBase:ident)?> $(+ $HdlCmpBase:ident)? @@ -729,6 +731,8 @@ macro_rules! impl_hdl_cmp { } $vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? { + $(const $TRY_STRUCTURAL_EQ: bool;)? + $(#[track_caller] fn $cmp_value_fn( $cmp_value_lhs: Self, @@ -912,6 +916,7 @@ impl_hdl_cmp! { #[ impl_helper = HdlPartialEqImplHelper, impl_helper_sealed = HdlPartialEqImplHelperSealed, + try_structural_eq = TRY_STRUCTURAL_EQ, ] pub trait HdlPartialEq: ValueType > diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index 5d335a5..7c5af38 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -22,7 +22,7 @@ use crate::{ Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue, }, - intern::{Intern, Interned}, + intern::{Intern, Interned, MemoizeGeneric}, phantom_const::{PhantomConst, PhantomConstValue}, reset::{ AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset, @@ -2984,6 +2984,7 @@ macro_rules! impl_compare_op { #[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)] #[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)] #[type($Lhs:ty, $Rhs:ty)] + $(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])? #[trait($Trait:ident)] $( struct $name:ident; @@ -3045,6 +3046,7 @@ macro_rules! impl_compare_op { })* impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs { + $(const $TRY_STRUCTURAL_EQ: bool = true;)? $(fn $value_method( _lhs: Self, $lhs_compare_value: Cow<'_, ::SimValue>, @@ -3065,6 +3067,7 @@ impl_compare_op! { #[to_dyn_type(lhs => lhs, rhs => rhs)] #[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)] #[type(Bool, Bool)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3088,6 +3091,7 @@ impl_compare_op! { #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())] #[type(UIntType, UIntType)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3112,6 +3116,7 @@ impl_compare_op! { #[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))] #[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())] #[type(SIntType, SIntType)] + #[try_structural_eq = TRY_STRUCTURAL_EQ] #[trait(HdlPartialEqImpl)] struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq(); struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne(); @@ -3133,6 +3138,8 @@ impl_compare_op! { macro_rules! impl_compare_forwards_to_bool { ($ty:ident) => { impl HdlPartialEqImpl for $ty { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -4948,3 +4955,270 @@ impl ToExpr for SimIoForGlobal { } } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[non_exhaustive] +pub struct StructuralEqFlags { + pub assume_padding_is_zeroed: bool, +} + +impl StructuralEqFlags { + pub const DEFAULT: Self = Self { + assume_padding_is_zeroed: false, + }; +} + +impl Default for StructuralEqFlags { + fn default() -> Self { + Self::DEFAULT + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[non_exhaustive] +pub enum StructuralEqError { + TypesAreNotEqual { + lhs: CanonicalType, + rhs: CanonicalType, + }, + TypeContainsSimOnly { + ty: CanonicalType, + }, +} + +impl fmt::Display for StructuralEqError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TypesAreNotEqual { lhs, rhs } => write!( + f, + "StructuralEq lhs type must be the same as rhs type:\nlhs: {lhs:#?}\nrhs: {rhs:#?}\n", + ), + Self::TypeContainsSimOnly { ty } => write!( + f, + "StructuralEq input type must not contain SimOnly type: {ty:#?}", + ), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct StructuralEq { + lhs: Expr, + rhs: Expr, + flags: StructuralEqFlags, + literal_bits: Result, NotALiteralExpr>, +} + +impl StructuralEq { + fn literal_eq( + ty: CanonicalType, + l: Interned, + r: Interned, + ) -> Result { + enum PairRefOrInternedBitSlice<'a> { + Ref(&'a BitSlice, &'a BitSlice), + Interned(Interned, Interned), + } + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize(CanonicalType); + impl MemoizeGeneric for MyMemoize { + type InputRef<'a> = (&'a BitSlice, &'a BitSlice); + type InputOwned = (Interned, Interned); + type InputCow<'a> = PairRefOrInternedBitSlice<'a>; + type Output = Result; + + 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::()[..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, rhs: Expr) -> Self { + Self::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT) + } + #[track_caller] + pub fn with_flags( + lhs: Expr, + rhs: Expr, + flags: StructuralEqFlags, + ) -> Self { + match Self::try_with_flags(lhs, rhs, flags) { + Ok(retval) => retval, + Err(e) => panic!("{e}"), + } + } + pub fn try_new( + lhs: Expr, + rhs: Expr, + ) -> Result { + Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT) + } + pub fn try_with_flags( + lhs: Expr, + rhs: Expr, + flags: StructuralEqFlags, + ) -> Result { + 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 { + self.lhs + } + pub fn rhs(self) -> Expr { + self.rhs + } + pub fn flags(self) -> StructuralEqFlags { + self.flags + } +} + +impl ToLiteralBits for StructuralEq { + fn to_literal_bits(&self) -> Result, 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 { + Expr { + __enum: ExprEnum::StructuralEq(*self).intern(), + __ty: Bool, + __flow: Flow::Source, + } + } +} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index d7775ec..84d3ace 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -63,7 +63,7 @@ pub struct TargetPathToTraceAsString { impl fmt::Display for TargetPathToTraceAsString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, ".to_trace_as_string(...)") + write!(f, ".to_trace_as_string()") } } diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 60cc0d1..cad55a8 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -7,7 +7,7 @@ use crate::{ bundle::{BundleField, BundleType}, enum_::{EnumType, EnumVariant}, expr::{ - ExprEnum, + CastToImpl, ExprEnum, ops::{self, VariantAccess}, target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, @@ -389,6 +389,7 @@ struct BlockDefinitionsCache { cast_bits_to_array_exprs: RefCell>, cast_bits_to_phantom_const_exprs: RefCell>, per_module_formal_inputs: RefCell>, + structural_eq_exprs: RefCell>, } struct BlockDefinitions<'a> { @@ -1774,6 +1775,143 @@ endmodule }, ) } + fn expr_structural_eq_bit>( + &mut self, + lhs: Expr, + rhs: Expr, + definitions: &BlockDefinitions<'_>, + const_ty: bool, + ) -> Result { + self.expr_binary( + "eq", + Expr::::from_canonical(lhs).cast_to(Bool), + Expr::::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 { + match ty { + CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => { + Ok(format!("eq({lhs}, {rhs})")) + } + CanonicalType::Array(ty) => { + if ty.len() == 1 { + return self.expr_structural_eq( + ty.element(), + lhs + "[0]", + rhs + "[0]", + definitions, + const_ty, + ); + } else if ty.is_empty() { + return Ok(self.bool_literal(true)); + } + definitions.get_or_write_definition( + (lhs, rhs), + |c| &c.structural_eq_exprs, + |definitions, (lhs, rhs)| { + let mut retval = None; + for array_index in 0..ty.len() { + let element_eq = self.expr_structural_eq( + ty.element(), + format!("{lhs}[{array_index}]"), + format!("{rhs}[{array_index}]"), + &definitions, + const_ty, + )?; + retval = match retval { + Some(old_eq) => { + let ident = self.module.ns.make_new("_array_structural_eq"); + definitions + .add_definition_line(format_args!("wire {ident}: UInt<1>")); + definitions.add_definition_line(format_args!( + "connect {ident}, and({old_eq}, {element_eq})" + )); + Some(ident.to_string()) + } + None => Some(element_eq), + }; + } + Ok(retval.expect("known to be Some")) + }, + ) + } + CanonicalType::Enum(ty) => { + let lhs = self.expr_cast_enum_to_bits( + lhs, + ty, + definitions, + Indent { + indent_depth: &Cell::new(0), + indent: self.indent.indent, + }, + )?; + let rhs = self.expr_cast_enum_to_bits( + rhs, + ty, + definitions, + Indent { + indent_depth: &Cell::new(0), + indent: self.indent.indent, + }, + )?; + Ok(format!("eq({lhs}, {rhs})")) + } + CanonicalType::Bundle(ty) => { + let fields = ty.fields(); + if fields.is_empty() { + return Ok(self.bool_literal(true)); + } + definitions.get_or_write_definition( + (lhs, rhs), + |c| &c.structural_eq_exprs, + |definitions, (lhs, rhs)| { + let mut retval = None; + for field in fields { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let field_eq = self.expr_structural_eq( + field.ty, + format!("{lhs}.{field_ident}"), + format!("{rhs}.{field_ident}"), + &definitions, + const_ty, + )?; + retval = match retval { + Some(old_eq) => { + let ident = self.module.ns.make_new("_bundle_structural_eq"); + definitions + .add_definition_line(format_args!("wire {ident}: UInt<1>")); + definitions.add_definition_line(format_args!( + "connect {ident}, and({old_eq}, {field_eq})" + )); + Some(ident.to_string()) + } + None => Some(field_eq), + }; + } + Ok(retval.expect("known to be Some")) + }, + ) + } + CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => Ok(format!("eq(asUInt({lhs}), asUInt({rhs}))")), + CanonicalType::PhantomConst(_) => Ok(self.bool_literal(true)), + CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + CanonicalType::TraceAsString(ty) => { + self.expr_structural_eq(ty.inner_ty(), lhs, rhs, definitions, const_ty) + } + } + } fn expr( &mut self, expr: Expr, @@ -2117,6 +2255,13 @@ endmodule ExprEnum::TraceAsStringAsInner(expr) => { self.expr(Expr::canonical(expr.arg()), definitions, const_ty) } + ExprEnum::StructuralEq(expr) => { + let ty = expr.lhs().ty(); + assert_eq!(ty, expr.rhs().ty()); + let lhs = self.expr(expr.lhs(), definitions, const_ty)?; + let rhs = self.expr(expr.rhs(), definitions, const_ty)?; + self.expr_structural_eq(ty, lhs, rhs, definitions, const_ty) + } ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()), ExprEnum::Instance(expr) => { assert!(!const_ty, "not a constant"); diff --git a/crates/fayalite/src/int/uint_in_range.rs b/crates/fayalite/src/int/uint_in_range.rs index edf2e25..4292d08 100644 --- a/crates/fayalite/src/int/uint_in_range.rs +++ b/crates/fayalite/src/int/uint_in_range.rs @@ -177,6 +177,8 @@ impl CastToImpl for Bool { } impl HdlPartialEqImpl for UIntInRangeMaskType { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -570,6 +572,8 @@ macro_rules! define_uint_in_range_type { HdlPartialEqImpl<$UIntInRangeType> for $UIntInRangeType { + const TRY_STRUCTURAL_EQ: bool = true; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -657,6 +661,8 @@ macro_rules! define_uint_in_range_type { impl HdlPartialEqImpl> for $UIntInRangeType { + const TRY_STRUCTURAL_EQ: bool = false; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, @@ -676,6 +682,8 @@ macro_rules! define_uint_in_range_type { impl HdlPartialEqImpl<$UIntInRangeType> for UIntType { + const TRY_STRUCTURAL_EQ: bool = false; + fn cmp_value_eq( _lhs: Self, lhs_value: Cow<'_, Self::SimValue>, diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 2535694..e899fd7 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -2206,6 +2206,7 @@ impl transform::visit::Visitor for AssertExprValidity<'_> { | ExprEnum::CastBitsTo(_) | ExprEnum::ToTraceAsString(_) | ExprEnum::TraceAsStringAsInner(_) + | ExprEnum::StructuralEq(_) | ExprEnum::FormalInput(_) => v.default_visit(self), ExprEnum::VariantAccess(_) | ExprEnum::ModuleIO(_) @@ -2247,7 +2248,7 @@ impl Module { clocks_for_past, simulation: Some(simulation), }) => { - let mut clocks_for_past_set = HashSet::default(); + let mut clocks_for_past_set = HashSet::::default(); *clocks_for_past = clocks_for_past .iter() .copied() @@ -2268,7 +2269,9 @@ impl Module { } if simulation.sim_io_to_generator_map.len() > module_io.len() { // if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io - let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io)); + let module_io_set = HashSet::>::from_iter( + module_io.iter().map(|v| v.module_io), + ); for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() { if !module_io_set.contains(&**sim_io) { panic!( diff --git a/crates/fayalite/src/module/transform.rs b/crates/fayalite/src/module/transform.rs index 063a1a3..7eec4cf 100644 --- a/crates/fayalite/src/module/transform.rs +++ b/crates/fayalite/src/module/transform.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information pub mod deduce_resets; +pub mod deduce_structural_eq_flags; pub mod simplify_enums; pub mod simplify_memories; pub mod visit; diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index 611401b..50a58c5 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -1208,6 +1208,7 @@ impl RunPass

for ExprEnum { Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) } ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1653,6 +1654,35 @@ impl RunPassExpr for ops::ToTraceAsString { } } +impl RunPassExpr for ops::StructuralEq { + type Args<'a> = [Expr; 2]; + + fn args<'a>(&'a self) -> Self::Args<'a> { + [self.lhs(), self.rhs()] + } + + fn source_location(&self) -> Option { + None + } + + fn union_parts( + &self, + _resets: Resets, + args_resets: Vec, + 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>, + ) -> Result { + Ok(Self::with_flags(new_args[0], new_args[1], self.flags())) + } +} + impl RunPassExpr for ModuleIO { type Args<'a> = [Expr; 0]; diff --git a/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs b/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs new file mode 100644 index 0000000..009293c --- /dev/null +++ b/crates/fayalite/src/module/transform/deduce_structural_eq_flags.rs @@ -0,0 +1,1606 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{ + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, + expr::{ + ExprEnum, ToLiteralBits, + ops::{ + ArrayIndex, FieldAccess, StructuralEq, StructuralEqFlags, TraceAsStringAsInner, + VariantAccess, + }, + target::TargetBase, + }, + intern::{Intern, InternSlice, Interned, MemoizeGeneric}, + module::{ + ModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtInstance, StmtReg, StmtWire, + transform::visit::{Fold, Folder, Visit, Visitor}, + }, + prelude::*, + util::{ + BitSliceWriteWithBase, HashMap, + indented_print::{PushIndent, indented_println}, + union_find_map::{Entry, UnionFindMap}, + }, +}; +use bitvec::{order::Lsb0, view::BitView}; +use std::{convert::Infallible, fmt}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum FlagsTree { + Enum { + variants: Interned<[Option>]>, + /// invariant -- if this is true all children must also have [`FlagsTree::assume_padding_is_zeroed()`] return true + assume_padding_is_zeroed: bool, + }, + Bundle { + fields: Interned<[Interned]>, + /// invariant -- if this is true all children must also have [`FlagsTree::assume_padding_is_zeroed()`] return true + assume_padding_is_zeroed: bool, + }, + NoPadding, +} + +impl fmt::Debug for FlagsTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Enum { + variants, + assume_padding_is_zeroed, + } => f + .debug_struct("Enum") + .field( + "variants", + &fmt::from_fn(|f| { + f.debug_list() + .entries(variants.iter().map(|variant| { + fmt::from_fn(move |f| match variant { + Some(variant) => variant.fmt(f), + None => f.write_str("None"), + }) + })) + .finish() + }), + ) + .field("assume_padding_is_zeroed", assume_padding_is_zeroed) + .finish(), + Self::Bundle { + fields, + assume_padding_is_zeroed, + } => f + .debug_struct("Bundle") + .field("fields", fields) + .field("assume_padding_is_zeroed", assume_padding_is_zeroed) + .finish(), + Self::NoPadding => f.write_str("NoPadding"), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum FlagsTreeSourceValue<'a> { + LiteralBits { bits: &'a BitSlice }, + Flags { assume_padding_is_zeroed: bool }, +} + +impl<'a> fmt::Debug for FlagsTreeSourceValue<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::LiteralBits { bits } => f + .debug_struct("LiteralBits") + .field( + "bits", + &fmt::from_fn(|f| write!(f, "{:#b}", BitSliceWriteWithBase(bits))), + ) + .finish(), + Self::Flags { + assume_padding_is_zeroed, + } => f + .debug_struct("Flags") + .field("assume_padding_is_zeroed", assume_padding_is_zeroed) + .finish(), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum FlagsTreeSourceValueOwned { + LiteralBits { bits: Interned }, + Flags { assume_padding_is_zeroed: bool }, +} + +impl FlagsTreeSourceValueOwned { + fn as_ref(&self) -> FlagsTreeSourceValue<'_> { + match *self { + Self::LiteralBits { ref bits } => FlagsTreeSourceValue::LiteralBits { bits }, + Self::Flags { + assume_padding_is_zeroed, + } => FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed, + }, + } + } +} + +impl<'a> FlagsTreeSourceValue<'a> { + fn to_owned(self) -> FlagsTreeSourceValueOwned { + match self { + Self::LiteralBits { bits } => FlagsTreeSourceValueOwned::LiteralBits { + bits: bits.intern(), + }, + Self::Flags { + assume_padding_is_zeroed, + } => FlagsTreeSourceValueOwned::Flags { + assume_padding_is_zeroed, + }, + } + } + fn visit_array_body>( + self, + element_ty: CanonicalType, + f: impl FnMut(Self) -> T, + ) -> R { + match self { + Self::LiteralBits { bits } => { + let bit_width = element_ty.bit_width(); + if bit_width == 0 { + R::from_iter([]) + } else { + bits.chunks(bit_width) + .map(|bits| Self::LiteralBits { bits }) + .map(f) + .collect() + } + } + Self::Flags { .. } => [self].into_iter().map(f).collect(), + } + } + fn visit_bundle_body>( + self, + bundle: Bundle, + mut f: impl FnMut(usize, &BundleField, Self) -> T, + ) -> R { + match self { + Self::LiteralBits { bits } => bundle + .fields() + .iter() + .enumerate() + .scan(bits, |bundle_bits, (field_index, field)| { + let field_bit_width = field.ty.bit_width(); + let bits; + (bits, *bundle_bits) = bundle_bits.split_at(field_bit_width); + Some(f(field_index, field, Self::LiteralBits { bits })) + }) + .collect(), + Self::Flags { .. } => bundle + .fields() + .iter() + .enumerate() + .map(move |(field_index, field)| f(field_index, field, self)) + .collect(), + } + } + fn visit_enum_body>( + self, + enum_: Enum, + debug_trace: bool, + mut f: impl FnMut(&EnumVariant, Self) -> T, + ) -> (R, bool) { + let collected; + let padding_is_zeroed; + match self { + Self::LiteralBits { bits } => { + let mut discriminant = 0usize; + let discriminant_bit_width = enum_.discriminant_bit_width(); + let (discriminant_bits, bits) = bits.split_at(discriminant_bit_width); + if debug_trace { + indented_println!( + "discriminant_bits={:#b}", + BitSliceWriteWithBase(discriminant_bits) + ); + } + discriminant.view_bits_mut::()[..discriminant_bit_width] + .copy_from_bitslice(discriminant_bits); + let (bits, padding) = bits.split_at( + enum_ + .variants() + .get(discriminant) + .and_then(|variant| variant.ty) + .map_or(0, |variant_ty| variant_ty.bit_width()), + ); + if debug_trace { + indented_println!( + "bits={:#b}\npadding={:#b}", + BitSliceWriteWithBase(bits), + BitSliceWriteWithBase(padding), + ); + } + collected = enum_ + .variants() + .iter() + .enumerate() + .map(|(variant_index, variant)| { + f( + variant, + if variant_index == discriminant { + Self::LiteralBits { bits } + } else { + Self::Flags { + assume_padding_is_zeroed: true, + } + }, + ) + }) + .collect(); + padding_is_zeroed = !padding.any(); + if debug_trace { + indented_println!("padding_is_zeroed={padding_is_zeroed:?}"); + } + } + Self::Flags { + assume_padding_is_zeroed, + } => { + collected = enum_ + .variants() + .iter() + .map(|variant| f(variant, self)) + .collect(); + padding_is_zeroed = assume_padding_is_zeroed; + } + } + (collected, padding_is_zeroed) + } +} + +impl FlagsTree { + fn contains_padding(&self) -> bool { + match self { + Self::NoPadding => false, + Self::Enum { .. } | Self::Bundle { .. } => true, + } + } + fn assume_padding_is_zeroed(&self) -> bool { + match *self { + Self::Enum { + assume_padding_is_zeroed, + .. + } + | Self::Bundle { + assume_padding_is_zeroed, + .. + } => assume_padding_is_zeroed, + Self::NoPadding => true, + } + } + fn new_inner<'a>( + ty: &CanonicalType, + source_value: FlagsTreeSourceValue<'a>, + debug_trace: bool, + ) -> Interned { + let _push_indent; + if debug_trace { + indented_println!("FlagsTree::new_inner()"); + _push_indent = PushIndent::new(); + indented_println!("ty: {ty:?}"); + indented_println!("source_value: {source_value:?}"); + } + let retval = match ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => Self::NoPadding.intern_sized(), + CanonicalType::Array(ty) => { + let mut retval = None; + let element_ty = ty.element(); + let () = + source_value.visit_array_body(element_ty, |source_value| match &mut retval { + Some(retval) => { + *retval = FlagsTree::new(element_ty, source_value, debug_trace) + .merged(*retval) + } + None => retval = Some(Self::new(element_ty, source_value, debug_trace)), + }); + retval.unwrap_or_else(|| Self::NoPadding.intern_sized()) + } + CanonicalType::Enum(ty) => { + let mut expected_bit_width = None; + let mut contains_padding = false; + let mut assume_padding_is_zeroed = true; + let (variants, padding_is_zeroed): (Vec<_>, _) = + source_value.visit_enum_body(*ty, debug_trace, |variant, source_value| { + let (variant_flags_tree, bit_width) = if let Some(variant_ty) = variant.ty { + let variant_flags_tree = + Self::new(variant_ty, source_value, debug_trace); + contains_padding |= variant_flags_tree.contains_padding(); + assume_padding_is_zeroed &= + variant_flags_tree.assume_padding_is_zeroed(); + (Some(variant_flags_tree), variant_ty.bit_width()) + } else { + (None, 0) + }; + if expected_bit_width + .replace(bit_width) + .is_some_and(|v| v != bit_width) + { + contains_padding = true; + } + variant_flags_tree + }); + assume_padding_is_zeroed &= padding_is_zeroed; + if contains_padding { + Self::Enum { + variants: variants.intern_slice(), + assume_padding_is_zeroed, + } + .intern_sized() + } else { + Self::NoPadding.intern_sized() + } + } + CanonicalType::Bundle(ty) => { + let mut contains_padding = false; + let mut assume_padding_is_zeroed = true; + let fields: Vec<_> = + source_value.visit_bundle_body(*ty, |_field_index, field, source_value| { + let flags_tree = Self::new(field.ty, source_value, debug_trace); + contains_padding |= flags_tree.contains_padding(); + assume_padding_is_zeroed &= flags_tree.assume_padding_is_zeroed(); + flags_tree + }); + if contains_padding { + Self::Bundle { + fields: fields.intern_slice(), + assume_padding_is_zeroed, + } + .intern_sized() + } else { + Self::NoPadding.intern_sized() + } + } + CanonicalType::TraceAsString(ty) => Self::new(ty.inner_ty(), source_value, debug_trace), + }; + if debug_trace { + indented_println!("return: {retval:#?}"); + } + retval + } + fn new( + ty: CanonicalType, + source_value: FlagsTreeSourceValue<'_>, + debug_trace: bool, + ) -> Interned { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize { + debug_trace: bool, + } + enum InputCow<'a> { + Borrowed { + ty: &'a CanonicalType, + source_value: FlagsTreeSourceValue<'a>, + }, + Owned { + ty: CanonicalType, + source_value: FlagsTreeSourceValueOwned, + }, + } + impl MemoizeGeneric for MyMemoize { + type InputRef<'a> = (&'a CanonicalType, FlagsTreeSourceValue<'a>); + type InputOwned = (CanonicalType, FlagsTreeSourceValueOwned); + type InputCow<'a> = InputCow<'a>; + type Output = Interned; + + fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool { + a == b + } + + fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> { + let (ty, source_value) = input; + (ty, source_value.as_ref()) + } + + fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned { + match input { + InputCow::Borrowed { ty, source_value } => (*ty, source_value.to_owned()), + InputCow::Owned { ty, source_value } => (ty, source_value), + } + } + + fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> { + match input { + &InputCow::Borrowed { ty, source_value } => (ty, source_value), + InputCow::Owned { ty, source_value } => (ty, source_value.as_ref()), + } + } + + fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> { + let (ty, source_value) = input; + InputCow::Owned { ty, source_value } + } + + fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> { + let (ty, source_value) = input; + InputCow::Borrowed { ty, source_value } + } + + fn inner(self, input: Self::InputRef<'_>) -> Self::Output { + let (ty, source_value) = input; + FlagsTree::new_inner(ty, source_value, self.debug_trace) + } + } + MyMemoize { debug_trace }.get((&ty, source_value)) + } + #[must_use] + fn merged(self, other: Interned) -> Interned { + if self == *other { + return other; + } + match (self, *other) { + ( + Self::Enum { + variants: l_variants, + assume_padding_is_zeroed: l_assume_padding_is_zeroed, + }, + Self::Enum { + variants: r_variants, + assume_padding_is_zeroed: r_assume_padding_is_zeroed, + }, + ) => { + let variants = Interned::from_iter(l_variants.iter().zip(&r_variants).map( + |(&l_variant, &r_variant)| { + l_variant + .zip(r_variant) + .map(|(l_variant, r_variant)| l_variant.merged(r_variant)) + }, + )); + let assume_padding_is_zeroed = + l_assume_padding_is_zeroed & r_assume_padding_is_zeroed; + Self::Enum { + variants, + assume_padding_is_zeroed, + } + .intern_sized() + } + (Self::Enum { .. }, _) => unreachable!("mismatched types"), + ( + Self::Bundle { + fields: l_fields, + assume_padding_is_zeroed: l_assume_padding_is_zeroed, + }, + Self::Bundle { + fields: r_fields, + assume_padding_is_zeroed: r_assume_padding_is_zeroed, + }, + ) => { + let fields = Interned::from_iter( + l_fields + .iter() + .zip(&r_fields) + .map(|(&l_field, &r_field)| l_field.merged(r_field)), + ); + let assume_padding_is_zeroed = + l_assume_padding_is_zeroed & r_assume_padding_is_zeroed; + Self::Bundle { + fields, + assume_padding_is_zeroed, + } + .intern_sized() + } + (Self::Bundle { .. }, _) => unreachable!("mismatched types"), + (Self::NoPadding, _) => { + unreachable!("NoPadding is always caught by the early return above") + } + } + } +} + +#[derive(Copy, Clone)] +enum ExprOrUnknown { + Expr(Expr), + Unknown(T), +} + +impl fmt::Debug for ExprOrUnknown { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Expr(expr) => expr.fmt(f), + Self::Unknown(ty) => f.debug_tuple("Unknown").field(ty).finish(), + } + } +} + +fn write_expr_path(expr: impl ToExpr, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write_expr_enum_path(&Expr::expr_enum(expr.to_expr()), f) +} + +fn write_expr_enum_path(expr: &ExprEnum, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_target_base( + target_base: impl Into, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{:?}", target_base.into().target_name()) + } + match expr { + ExprEnum::FieldAccess(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, ".{}", expr.field_name()) + } + ExprEnum::VariantAccess(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, ".<{}>", expr.variant_name()) + } + ExprEnum::ArrayIndex(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, "[{}]", expr.element_index()) + } + ExprEnum::DynArrayIndex(expr) => { + write_expr_path(expr.base(), f)?; + write!(f, "[...]") + } + ExprEnum::ToTraceAsString(expr) => { + write_expr_path(expr.inner(), f)?; + write!(f, ".to_trace_as_string()") + } + ExprEnum::TraceAsStringAsInner(expr) => { + write_expr_path(expr.arg(), f)?; + write!(f, ".") + } + ExprEnum::ModuleIO(expr) => fmt_target_base(*expr, f), + ExprEnum::Instance(expr) => fmt_target_base(*expr, f), + ExprEnum::Wire(expr) => fmt_target_base(*expr, f), + ExprEnum::Reg(expr) => fmt_target_base(*expr, f), + ExprEnum::RegSync(expr) => fmt_target_base(*expr, f), + ExprEnum::RegAsync(expr) => fmt_target_base(*expr, f), + ExprEnum::MemPort(expr) => fmt_target_base(*expr, f), + ExprEnum::FormalInput(expr) => fmt_target_base(*expr, f), + + ExprEnum::UIntLiteral(_) + | ExprEnum::SIntLiteral(_) + | ExprEnum::BoolLiteral(_) + | ExprEnum::PhantomConst(_) + | ExprEnum::BundleLiteral(_) + | ExprEnum::ArrayLiteral(_) + | ExprEnum::EnumLiteral(_) + | ExprEnum::Uninit(_) + | ExprEnum::NotU(_) + | ExprEnum::NotS(_) + | ExprEnum::NotB(_) + | ExprEnum::Neg(_) + | ExprEnum::BitAndU(_) + | ExprEnum::BitAndS(_) + | ExprEnum::BitAndB(_) + | ExprEnum::BitOrU(_) + | ExprEnum::BitOrS(_) + | ExprEnum::BitOrB(_) + | ExprEnum::BitXorU(_) + | ExprEnum::BitXorS(_) + | ExprEnum::BitXorB(_) + | ExprEnum::AddU(_) + | ExprEnum::AddS(_) + | ExprEnum::SubU(_) + | ExprEnum::SubS(_) + | ExprEnum::MulU(_) + | ExprEnum::MulS(_) + | ExprEnum::DivU(_) + | ExprEnum::DivS(_) + | ExprEnum::RemU(_) + | ExprEnum::RemS(_) + | ExprEnum::DynShlU(_) + | ExprEnum::DynShlS(_) + | ExprEnum::DynShrU(_) + | ExprEnum::DynShrS(_) + | ExprEnum::FixedShlU(_) + | ExprEnum::FixedShlS(_) + | ExprEnum::FixedShrU(_) + | ExprEnum::FixedShrS(_) + | ExprEnum::CmpLtB(_) + | ExprEnum::CmpLeB(_) + | ExprEnum::CmpGtB(_) + | ExprEnum::CmpGeB(_) + | ExprEnum::CmpEqB(_) + | ExprEnum::CmpNeB(_) + | ExprEnum::CmpLtU(_) + | ExprEnum::CmpLeU(_) + | ExprEnum::CmpGtU(_) + | ExprEnum::CmpGeU(_) + | ExprEnum::CmpEqU(_) + | ExprEnum::CmpNeU(_) + | ExprEnum::CmpLtS(_) + | ExprEnum::CmpLeS(_) + | ExprEnum::CmpGtS(_) + | ExprEnum::CmpGeS(_) + | ExprEnum::CmpEqS(_) + | ExprEnum::CmpNeS(_) + | ExprEnum::CastUIntToUInt(_) + | ExprEnum::CastUIntToSInt(_) + | ExprEnum::CastSIntToUInt(_) + | ExprEnum::CastSIntToSInt(_) + | ExprEnum::CastBoolToUInt(_) + | ExprEnum::CastBoolToSInt(_) + | ExprEnum::CastUIntToBool(_) + | ExprEnum::CastSIntToBool(_) + | ExprEnum::CastBoolToSyncReset(_) + | ExprEnum::CastUIntToSyncReset(_) + | ExprEnum::CastSIntToSyncReset(_) + | ExprEnum::CastBoolToAsyncReset(_) + | ExprEnum::CastUIntToAsyncReset(_) + | ExprEnum::CastSIntToAsyncReset(_) + | ExprEnum::CastSyncResetToBool(_) + | ExprEnum::CastSyncResetToUInt(_) + | ExprEnum::CastSyncResetToSInt(_) + | ExprEnum::CastSyncResetToReset(_) + | ExprEnum::CastAsyncResetToBool(_) + | ExprEnum::CastAsyncResetToUInt(_) + | ExprEnum::CastAsyncResetToSInt(_) + | ExprEnum::CastAsyncResetToReset(_) + | ExprEnum::CastResetToBool(_) + | ExprEnum::CastResetToUInt(_) + | ExprEnum::CastResetToSInt(_) + | ExprEnum::CastBoolToClock(_) + | ExprEnum::CastUIntToClock(_) + | ExprEnum::CastSIntToClock(_) + | ExprEnum::CastClockToBool(_) + | ExprEnum::CastClockToUInt(_) + | ExprEnum::CastClockToSInt(_) + | ExprEnum::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) + | ExprEnum::CastBitsTo(_) + | ExprEnum::StructuralEq(_) + | ExprEnum::SimIoForGlobal(_) => write!(f, "..."), + } +} + +fn display_expr_enum_path(expr: ExprEnum) -> impl fmt::Display { + fmt::from_fn(move |f| write_expr_enum_path(&expr, f)) +} + +fn display_expr_path(expr: impl ToExpr) -> impl fmt::Display { + display_expr_enum_path(*Expr::expr_enum(expr.to_expr())) +} + +impl fmt::Display for ExprOrUnknown { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_target_base( + target_base: impl Into, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{:?}", target_base.into().target_name()) + } + match *self { + Self::Expr(expr) => match *Expr::expr_enum(expr) { + ExprEnum::FieldAccess(expr) => { + ExprOrUnknown::Expr(expr.base()).fmt(f)?; + write!(f, ".{}", expr.field_name()) + } + ExprEnum::VariantAccess(expr) => { + ExprOrUnknown::Expr(expr.base()).fmt(f)?; + write!(f, ".<{}>", expr.variant_name()) + } + ExprEnum::ArrayIndex(expr) => { + ExprOrUnknown::Expr(expr.base()).fmt(f)?; + write!(f, "[{}]", expr.element_index()) + } + ExprEnum::DynArrayIndex(expr) => { + ExprOrUnknown::Expr(expr.base()).fmt(f)?; + write!(f, "[...]") + } + ExprEnum::ToTraceAsString(expr) => { + ExprOrUnknown::Expr(expr.inner()).fmt(f)?; + write!(f, ".to_trace_as_string()") + } + ExprEnum::TraceAsStringAsInner(expr) => { + ExprOrUnknown::Expr(expr.arg()).fmt(f)?; + write!(f, ".") + } + ExprEnum::ModuleIO(expr) => fmt_target_base(expr, f), + ExprEnum::Instance(expr) => fmt_target_base(expr, f), + ExprEnum::Wire(expr) => fmt_target_base(expr, f), + ExprEnum::Reg(expr) => fmt_target_base(expr, f), + ExprEnum::RegSync(expr) => fmt_target_base(expr, f), + ExprEnum::RegAsync(expr) => fmt_target_base(expr, f), + ExprEnum::MemPort(expr) => fmt_target_base(expr, f), + ExprEnum::FormalInput(expr) => fmt_target_base(expr, f), + + ExprEnum::UIntLiteral(_) + | ExprEnum::SIntLiteral(_) + | ExprEnum::BoolLiteral(_) + | ExprEnum::PhantomConst(_) + | ExprEnum::BundleLiteral(_) + | ExprEnum::ArrayLiteral(_) + | ExprEnum::EnumLiteral(_) + | ExprEnum::Uninit(_) + | ExprEnum::NotU(_) + | ExprEnum::NotS(_) + | ExprEnum::NotB(_) + | ExprEnum::Neg(_) + | ExprEnum::BitAndU(_) + | ExprEnum::BitAndS(_) + | ExprEnum::BitAndB(_) + | ExprEnum::BitOrU(_) + | ExprEnum::BitOrS(_) + | ExprEnum::BitOrB(_) + | ExprEnum::BitXorU(_) + | ExprEnum::BitXorS(_) + | ExprEnum::BitXorB(_) + | ExprEnum::AddU(_) + | ExprEnum::AddS(_) + | ExprEnum::SubU(_) + | ExprEnum::SubS(_) + | ExprEnum::MulU(_) + | ExprEnum::MulS(_) + | ExprEnum::DivU(_) + | ExprEnum::DivS(_) + | ExprEnum::RemU(_) + | ExprEnum::RemS(_) + | ExprEnum::DynShlU(_) + | ExprEnum::DynShlS(_) + | ExprEnum::DynShrU(_) + | ExprEnum::DynShrS(_) + | ExprEnum::FixedShlU(_) + | ExprEnum::FixedShlS(_) + | ExprEnum::FixedShrU(_) + | ExprEnum::FixedShrS(_) + | ExprEnum::CmpLtB(_) + | ExprEnum::CmpLeB(_) + | ExprEnum::CmpGtB(_) + | ExprEnum::CmpGeB(_) + | ExprEnum::CmpEqB(_) + | ExprEnum::CmpNeB(_) + | ExprEnum::CmpLtU(_) + | ExprEnum::CmpLeU(_) + | ExprEnum::CmpGtU(_) + | ExprEnum::CmpGeU(_) + | ExprEnum::CmpEqU(_) + | ExprEnum::CmpNeU(_) + | ExprEnum::CmpLtS(_) + | ExprEnum::CmpLeS(_) + | ExprEnum::CmpGtS(_) + | ExprEnum::CmpGeS(_) + | ExprEnum::CmpEqS(_) + | ExprEnum::CmpNeS(_) + | ExprEnum::CastUIntToUInt(_) + | ExprEnum::CastUIntToSInt(_) + | ExprEnum::CastSIntToUInt(_) + | ExprEnum::CastSIntToSInt(_) + | ExprEnum::CastBoolToUInt(_) + | ExprEnum::CastBoolToSInt(_) + | ExprEnum::CastUIntToBool(_) + | ExprEnum::CastSIntToBool(_) + | ExprEnum::CastBoolToSyncReset(_) + | ExprEnum::CastUIntToSyncReset(_) + | ExprEnum::CastSIntToSyncReset(_) + | ExprEnum::CastBoolToAsyncReset(_) + | ExprEnum::CastUIntToAsyncReset(_) + | ExprEnum::CastSIntToAsyncReset(_) + | ExprEnum::CastSyncResetToBool(_) + | ExprEnum::CastSyncResetToUInt(_) + | ExprEnum::CastSyncResetToSInt(_) + | ExprEnum::CastSyncResetToReset(_) + | ExprEnum::CastAsyncResetToBool(_) + | ExprEnum::CastAsyncResetToUInt(_) + | ExprEnum::CastAsyncResetToSInt(_) + | ExprEnum::CastAsyncResetToReset(_) + | ExprEnum::CastResetToBool(_) + | ExprEnum::CastResetToUInt(_) + | ExprEnum::CastResetToSInt(_) + | ExprEnum::CastBoolToClock(_) + | ExprEnum::CastUIntToClock(_) + | ExprEnum::CastSIntToClock(_) + | ExprEnum::CastClockToBool(_) + | ExprEnum::CastClockToUInt(_) + | ExprEnum::CastClockToSInt(_) + | ExprEnum::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) + | ExprEnum::CastBitsTo(_) + | ExprEnum::StructuralEq(_) + | ExprEnum::SimIoForGlobal(_) => write!(f, "..."), + }, + Self::Unknown(_ty) => write!(f, "Unknown(...)"), + } + } +} + +impl From> for ExprOrUnknown { + fn from(expr: Expr) -> Self { + Self::Expr(expr) + } +} + +impl ExprOrUnknown { + fn ty(self) -> T { + match self { + Self::Expr(expr) => expr.ty(), + Self::Unknown(ty) => ty, + } + } + fn map( + self, + map_ty: impl FnOnce(T) -> U, + map_expr: impl FnOnce(Expr) -> Expr, + ) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(map_expr(expr)), + Self::Unknown(ty) => ExprOrUnknown::Unknown(map_ty(ty)), + } + } + fn from_canonical(v: ExprOrUnknown) -> Self { + match v { + ExprOrUnknown::Expr(expr) => Self::Expr(Expr::from_canonical(expr)), + ExprOrUnknown::Unknown(ty) => Self::Unknown(T::from_canonical(ty)), + } + } +} + +impl ExprOrUnknown { + fn field_at_index(self, field_index: usize) -> ExprOrUnknown { + self.map( + |ty| ty.fields()[field_index].ty, + |expr| FieldAccess::new_by_index(expr, field_index).to_expr(), + ) + } +} + +impl ExprOrUnknown { + fn variant_at_index(self, variant_index: usize) -> Option> { + match self { + Self::Expr(expr) => { + expr.ty().variants()[variant_index].ty?; + Some(ExprOrUnknown::Expr( + VariantAccess::new_by_index(expr, variant_index).to_expr(), + )) + } + Self::Unknown(ty) => Some(ExprOrUnknown::Unknown(ty.variants()[variant_index].ty?)), + } + } +} + +impl ExprOrUnknown { + fn element(self, element_index: usize) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(ArrayIndex::new(expr, element_index).to_expr()), + Self::Unknown(ty) => ExprOrUnknown::Unknown(ty.element()), + } + } +} + +impl ExprOrUnknown { + fn inner(self) -> ExprOrUnknown { + match self { + Self::Expr(expr) => ExprOrUnknown::Expr(TraceAsStringAsInner::new(expr).to_expr()), + Self::Unknown(ty) => ExprOrUnknown::Unknown(ty.inner_ty()), + } + } +} + +#[derive(Debug)] +struct State { + root_module: Interned>, + debug_trace: bool, + any_changes: bool, + expr_flags: UnionFindMap, Interned>, + exprs_visited: HashMap, bool>, + modules_visited: HashMap>, bool>, +} + +impl State { + fn new(root_module: Interned>, debug_trace: bool) -> Self { + Self { + root_module, + debug_trace, + any_changes: false, + expr_flags: UnionFindMap::default(), + exprs_visited: HashMap::default(), + modules_visited: HashMap::default(), + } + } + fn merge_expr_flags( + &mut self, + expr: Interned, + new_flags: FlagsTree, + ) -> Interned { + match self.expr_flags.entry(expr) { + Entry::Vacant(entry) => { + let new_flags = new_flags.intern_sized(); + entry.insert(new_flags); + self.any_changes = true; + new_flags + } + Entry::Occupied(mut entry) => { + let merged_flags = new_flags.merged(*entry.get()); + if merged_flags != *entry.get() { + if self.debug_trace { + indented_println!( + "merge_expr_flags({}):\n\ + old flags: {:#?}\n\ + new_flags: {new_flags:#?}\n\ + merged_flags: {merged_flags:#?}", + display_expr_enum_path(*expr), + entry.get(), + ); + } + self.any_changes = true; + } else if self.debug_trace { + if *merged_flags != new_flags { + indented_println!( + "merge_expr_flags({}):\n\ + flags (unchanged): {:#?}\n\ + new_flags: {new_flags:#?}", + display_expr_enum_path(*expr), + entry.get(), + ); + } else { + indented_println!( + "merge_expr_flags({}):\n\ + flags (unchanged): {:#?}", + display_expr_enum_path(*expr), + entry.get(), + ); + } + } + entry.insert(merged_flags); + merged_flags + } + } + } + fn union_exprs( + &mut self, + expr1: Interned, + expr2: Interned, + ) -> Interned { + let (unioned, value) = self + .expr_flags + .union(&expr1, &expr2, |_, v1, _, v2| v1.merged(v2)); + self.any_changes |= unioned; + *value + } + fn visit_expr_or_unknown(&mut self, expr: ExprOrUnknown) -> Interned { + match expr { + ExprOrUnknown::Expr(expr) => self.visit_canonical_expr(expr), + ExprOrUnknown::Unknown(ty) => FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: false, + }, + self.debug_trace, + ), + } + } + fn connect( + &mut self, + lhs: impl Into>, + rhs: impl Into>, + ) -> (Interned, Interned) { + let lhs = lhs.into(); + let rhs = rhs.into(); + let _push_indent; + if self.debug_trace { + indented_println!("connect({lhs}, {rhs}):"); + _push_indent = PushIndent::new(); + indented_println!("lhs: {lhs:?}"); + indented_println!("rhs: {rhs:?}"); + } + let lhs_ty = lhs.ty(); + let lhs_flags = self.visit_expr_or_unknown(lhs); + let rhs_flags = self.visit_expr_or_unknown(rhs); + if lhs_flags == rhs_flags { + return (lhs_flags, rhs_flags); + } + let (mut lhs_flags, mut rhs_flags) = match lhs_ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => { + unreachable!("flags are always FlagsTree::NoPadding") + } + CanonicalType::Array(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.len(), rhs.ty().len()); + assert!(lhs_ty.len() > 0); + // FlagsTree treats arrays transparently, so the returned flags don't need to be adjusted. + // All array indexing operations are unioned together so just arbitrarily use index 0 + self.connect(lhs.element(0), rhs.element(0)) + } + CanonicalType::Enum(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.variants().len(), rhs.ty().variants().len()); + let mut lhs_assume_padding_is_zeroed = + lhs_flags.assume_padding_is_zeroed() & rhs_flags.assume_padding_is_zeroed(); + let mut lhs_variants = Vec::with_capacity(lhs_ty.variants().len()); + for variant_index in 0..lhs_ty.variants().len() { + let lhs_variant = lhs.variant_at_index(variant_index); + let rhs_variant = rhs.variant_at_index(variant_index); + assert_eq!(lhs_variant.is_some(), rhs_variant.is_some()); + if let Some(lhs_variant) = lhs_variant + && let Some(rhs_variant) = rhs_variant + { + let (lhs_field_flags, _rhs_field_flags) = + self.connect(lhs_variant, rhs_variant); + lhs_variants.push(Some(lhs_field_flags)); + lhs_assume_padding_is_zeroed &= lhs_field_flags.assume_padding_is_zeroed(); + } else { + lhs_variants.push(None); + } + } + let lhs_flags = FlagsTree::Enum { + variants: lhs_variants.intern_slice(), + assume_padding_is_zeroed: lhs_assume_padding_is_zeroed, + } + .intern_sized(); + (lhs_flags, rhs_flags) + } + CanonicalType::Bundle(lhs_ty) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::::from_canonical(rhs); + assert_eq!(lhs_ty.fields().len(), rhs.ty().fields().len()); + let mut lhs_assume_padding_is_zeroed = lhs_flags.assume_padding_is_zeroed(); + let mut rhs_assume_padding_is_zeroed = rhs_flags.assume_padding_is_zeroed(); + let mut lhs_fields = Vec::with_capacity(lhs_ty.fields().len()); + let mut rhs_fields = Vec::with_capacity(lhs_ty.fields().len()); + for (field_index, (lhs_field, rhs_field)) in lhs_ty + .fields() + .into_iter() + .zip(rhs.ty().fields()) + .enumerate() + { + assert_eq!(lhs_field.flipped, rhs_field.flipped); + let lhs_field_flags; + let rhs_field_flags; + if lhs_field.flipped { + // flipped, so exchange lhs/rhs when recursively calling connect + (rhs_field_flags, lhs_field_flags) = self.connect( + rhs.field_at_index(field_index), + lhs.field_at_index(field_index), + ); + } else { + (lhs_field_flags, rhs_field_flags) = self.connect( + lhs.field_at_index(field_index), + rhs.field_at_index(field_index), + ); + } + lhs_fields.push(lhs_field_flags); + rhs_fields.push(rhs_field_flags); + lhs_assume_padding_is_zeroed &= lhs_field_flags.assume_padding_is_zeroed(); + rhs_assume_padding_is_zeroed &= rhs_field_flags.assume_padding_is_zeroed(); + } + let lhs_flags = FlagsTree::Bundle { + fields: lhs_fields.intern_slice(), + assume_padding_is_zeroed: lhs_assume_padding_is_zeroed, + } + .intern_sized(); + let rhs_flags = FlagsTree::Bundle { + fields: rhs_fields.intern_slice(), + assume_padding_is_zeroed: rhs_assume_padding_is_zeroed, + } + .intern_sized(); + (lhs_flags, rhs_flags) + } + CanonicalType::TraceAsString(_) => { + let lhs = ExprOrUnknown::from_canonical(lhs); + let rhs = ExprOrUnknown::from_canonical(rhs); + // FlagsTree treats TraceAsString transparently, so the returned flags don't need to be adjusted. + // this expression and the inner expression are unioned together + self.connect(lhs.inner(), rhs.inner()) + } + }; + if let ExprOrUnknown::Expr(lhs) = lhs { + lhs_flags = self.merge_expr_flags(Expr::expr_enum(lhs), *lhs_flags); + } + if let ExprOrUnknown::Expr(rhs) = rhs { + rhs_flags = self.merge_expr_flags(Expr::expr_enum(rhs), *rhs_flags); + } + let retval = (lhs_flags, rhs_flags); + if self.debug_trace { + indented_println!("returned: {retval:#?}"); + } + retval + } + fn visit_canonical_expr(&mut self, expr: Expr) -> Interned { + let expr_enum = Expr::expr_enum(expr); + let ty = expr.ty(); + let visited = self.exprs_visited.entry(expr_enum).or_insert(false); + let flags = *self.expr_flags.entry(expr_enum).or_insert_with(|| { + self.any_changes = true; + FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: true, + }, + self.debug_trace, + ) + }); + if std::mem::replace(visited, true) { + return flags; + } + let handle_array_index = |this: &mut Self, base: Expr| -> FlagsTree { + this.visit_canonical_expr(Expr::canonical(base)); + // FlagsTree treats arrays transparently, so just union them together. + *this.union_exprs(Expr::expr_enum(base), expr_enum) + }; + let handle_reg = |this: &mut Self, init: Option>| -> FlagsTree { + let init = match init { + Some(init) => ExprOrUnknown::Expr(init), + None => ExprOrUnknown::Unknown(ty), + }; + let (flags, _) = this.connect(ExprOrUnknown::Expr(expr), init); + *flags + }; + let literal_bits = expr_enum.to_literal_bits(); + let flags = match *expr_enum { + _ if literal_bits.is_ok() => { + let Ok(bits) = &literal_bits else { + unreachable!(); + }; + *FlagsTree::new( + ty, + FlagsTreeSourceValue::LiteralBits { bits }, + self.debug_trace, + ) + } + ExprEnum::UIntLiteral(_) + | ExprEnum::SIntLiteral(_) + | ExprEnum::BoolLiteral(_) + | ExprEnum::PhantomConst(_) => *flags, + ExprEnum::BundleLiteral(bundle_literal) => { + let expr = Expr::::from_canonical(expr); + let ty = bundle_literal.ty(); + let mut assume_padding_is_zeroed = flags.assume_padding_is_zeroed(); + let mut fields = Vec::with_capacity(ty.fields().len()); + for (field_index, field) in ty.fields().into_iter().enumerate() { + assert!(!field.flipped); + let (field_flags, _) = self.connect( + FieldAccess::new_by_index(expr, field_index).to_expr(), + bundle_literal.field_values()[field_index], + ); + fields.push(field_flags); + assume_padding_is_zeroed &= field_flags.assume_padding_is_zeroed(); + } + if let FlagsTree::NoPadding = *flags { + *flags + } else { + FlagsTree::Bundle { + fields: fields.intern_slice(), + assume_padding_is_zeroed, + } + } + } + ExprEnum::ArrayLiteral(array_literal) => { + let expr = Expr::::from_canonical(expr); + for (element_index, element_value) in + array_literal.element_values().into_iter().enumerate() + { + let array_index = ArrayIndex::new(expr, element_index).to_expr(); + self.visit_canonical_expr(array_index); + self.union_exprs(expr_enum, Expr::expr_enum(array_index)); + self.connect(array_index, element_value); + } + *flags + } + ExprEnum::EnumLiteral(enum_literal) => { + let expr = Expr::::from_canonical(expr); + let variant_access = + VariantAccess::new_by_index(expr, enum_literal.variant_index()).to_expr(); + self.visit_canonical_expr(variant_access); + if let Some(variant_value) = enum_literal.variant_value() { + self.connect(variant_access, variant_value); + } + *flags + } + ExprEnum::Uninit(_) => *FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: false, + }, + self.debug_trace, + ), + ExprEnum::NotU(_) + | ExprEnum::NotS(_) + | ExprEnum::NotB(_) + | ExprEnum::Neg(_) + | ExprEnum::BitAndU(_) + | ExprEnum::BitAndS(_) + | ExprEnum::BitAndB(_) + | ExprEnum::BitOrU(_) + | ExprEnum::BitOrS(_) + | ExprEnum::BitOrB(_) + | ExprEnum::BitXorU(_) + | ExprEnum::BitXorS(_) + | ExprEnum::BitXorB(_) + | ExprEnum::AddU(_) + | ExprEnum::AddS(_) + | ExprEnum::SubU(_) + | ExprEnum::SubS(_) + | ExprEnum::MulU(_) + | ExprEnum::MulS(_) + | ExprEnum::DivU(_) + | ExprEnum::DivS(_) + | ExprEnum::RemU(_) + | ExprEnum::RemS(_) + | ExprEnum::DynShlU(_) + | ExprEnum::DynShlS(_) + | ExprEnum::DynShrU(_) + | ExprEnum::DynShrS(_) + | ExprEnum::FixedShlU(_) + | ExprEnum::FixedShlS(_) + | ExprEnum::FixedShrU(_) + | ExprEnum::FixedShrS(_) + | ExprEnum::CmpLtB(_) + | ExprEnum::CmpLeB(_) + | ExprEnum::CmpGtB(_) + | ExprEnum::CmpGeB(_) + | ExprEnum::CmpEqB(_) + | ExprEnum::CmpNeB(_) + | ExprEnum::CmpLtU(_) + | ExprEnum::CmpLeU(_) + | ExprEnum::CmpGtU(_) + | ExprEnum::CmpGeU(_) + | ExprEnum::CmpEqU(_) + | ExprEnum::CmpNeU(_) + | ExprEnum::CmpLtS(_) + | ExprEnum::CmpLeS(_) + | ExprEnum::CmpGtS(_) + | ExprEnum::CmpGeS(_) + | ExprEnum::CmpEqS(_) + | ExprEnum::CmpNeS(_) + | ExprEnum::CastUIntToUInt(_) + | ExprEnum::CastUIntToSInt(_) + | ExprEnum::CastSIntToUInt(_) + | ExprEnum::CastSIntToSInt(_) + | ExprEnum::CastBoolToUInt(_) + | ExprEnum::CastBoolToSInt(_) + | ExprEnum::CastUIntToBool(_) + | ExprEnum::CastSIntToBool(_) + | ExprEnum::CastBoolToSyncReset(_) + | ExprEnum::CastUIntToSyncReset(_) + | ExprEnum::CastSIntToSyncReset(_) + | ExprEnum::CastBoolToAsyncReset(_) + | ExprEnum::CastUIntToAsyncReset(_) + | ExprEnum::CastSIntToAsyncReset(_) + | ExprEnum::CastSyncResetToBool(_) + | ExprEnum::CastSyncResetToUInt(_) + | ExprEnum::CastSyncResetToSInt(_) + | ExprEnum::CastSyncResetToReset(_) + | ExprEnum::CastAsyncResetToBool(_) + | ExprEnum::CastAsyncResetToUInt(_) + | ExprEnum::CastAsyncResetToSInt(_) + | ExprEnum::CastAsyncResetToReset(_) + | ExprEnum::CastResetToBool(_) + | ExprEnum::CastResetToUInt(_) + | ExprEnum::CastResetToSInt(_) + | ExprEnum::CastBoolToClock(_) + | ExprEnum::CastUIntToClock(_) + | ExprEnum::CastSIntToClock(_) + | ExprEnum::CastClockToBool(_) + | ExprEnum::CastClockToUInt(_) + | ExprEnum::CastClockToSInt(_) => *flags, + ExprEnum::FieldAccess(field_access) => { + let base_flags = self.visit_canonical_expr(Expr::canonical(field_access.base())); + match *base_flags { + FlagsTree::Enum { .. } => unreachable!(), + FlagsTree::Bundle { + fields, + assume_padding_is_zeroed, + } => { + let field_flags = fields[field_access.field_index()]; + let flags = field_flags.merged(flags); + if flags != field_flags { + self.merge_expr_flags( + Expr::expr_enum(field_access.base()), + FlagsTree::Bundle { + fields: fields + .iter() + .enumerate() + .map(|(i, field)| { + if i == field_access.field_index() { + flags + } else { + *field + } + }) + .collect(), + assume_padding_is_zeroed: assume_padding_is_zeroed + & flags.assume_padding_is_zeroed(), + }, + ); + } + *flags + } + FlagsTree::NoPadding => *flags, + } + } + ExprEnum::VariantAccess(variant_access) => { + let base_flags = self.visit_canonical_expr(Expr::canonical(variant_access.base())); + match *base_flags { + FlagsTree::Enum { + variants, + assume_padding_is_zeroed, + } => { + if let Some(variant_flags) = variants[variant_access.variant_index()] { + let flags = variant_flags.merged(flags); + if flags != variant_flags { + self.merge_expr_flags( + Expr::expr_enum(variant_access.base()), + FlagsTree::Enum { + variants: variants + .iter() + .enumerate() + .map(|(i, field)| { + if i == variant_access.variant_index() { + Some(flags) + } else { + *field + } + }) + .collect(), + assume_padding_is_zeroed: assume_padding_is_zeroed + & flags.assume_padding_is_zeroed(), + }, + ); + } + *flags + } else { + *flags + } + } + FlagsTree::Bundle { .. } => unreachable!(), + FlagsTree::NoPadding => *flags, + } + } + ExprEnum::ArrayIndex(expr) => handle_array_index(self, expr.base()), + ExprEnum::DynArrayIndex(expr) => handle_array_index(self, expr.base()), + ExprEnum::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) => *flags, + ExprEnum::CastBitsTo(_) => *FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: false, + }, + self.debug_trace, + ), + ExprEnum::ToTraceAsString(expr) => { + self.visit_canonical_expr(Expr::canonical(expr.inner())); + // FlagsTree treats TraceAsString transparently, so just union them together. + *self.union_exprs(Expr::expr_enum(expr.inner()), expr_enum) + } + ExprEnum::TraceAsStringAsInner(expr) => { + self.visit_canonical_expr(Expr::canonical(expr.arg())); + // FlagsTree treats TraceAsString transparently, so just union them together. + *self.union_exprs(Expr::expr_enum(expr.arg()), expr_enum) + } + ExprEnum::StructuralEq(_) => *flags, + ExprEnum::ModuleIO(_) => *flags, + ExprEnum::Instance(instance) => { + let expr = Expr::::from_canonical(expr); + for (field_index, module_io) in + instance.instantiated().module_io().into_iter().enumerate() + { + let module_io = module_io.module_io.to_expr(); + let field_access = FieldAccess::new_by_index(expr, field_index).to_expr(); + self.visit_canonical_expr(module_io); + self.visit_canonical_expr(field_access); + self.union_exprs(Expr::expr_enum(field_access), Expr::expr_enum(module_io)); + } + *flags + } + ExprEnum::Wire(_) => *flags, + ExprEnum::Reg(reg) => handle_reg(self, reg.init()), + ExprEnum::RegSync(reg) => handle_reg(self, reg.init()), + ExprEnum::RegAsync(reg) => handle_reg(self, reg.init()), + ExprEnum::MemPort(_) => *FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: false, + }, + self.debug_trace, + ), + ExprEnum::FormalInput(_) => *FlagsTree::new( + ty, + FlagsTreeSourceValue::Flags { + assume_padding_is_zeroed: false, + }, + self.debug_trace, + ), + ExprEnum::SimIoForGlobal(_) => { + unreachable!("Module is known to not contain SimIoForGlobal from validation") + } + }; + self.merge_expr_flags(expr_enum, flags); + let Ok(()) = expr_enum.default_visit(self); + *self.expr_flags.find_mut(&expr_enum) + } +} + +impl Visitor for State { + type Error = Infallible; + + fn visit_expr_enum(&mut self, expr_enum: &ExprEnum) -> Result<(), Self::Error> { + self.visit_canonical_expr(expr_enum.to_expr()); + Ok(()) + } + + fn visit_stmt_declaration(&mut self, stmt: &StmtDeclaration) -> Result<(), Self::Error> { + match stmt { + StmtDeclaration::Wire(StmtWire { + annotations: _, + wire, + }) => self.visit_canonical_expr(wire.to_expr()), + StmtDeclaration::Reg(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::RegSync(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::RegAsync(StmtReg { + annotations: _, + reg, + }) => self.visit_canonical_expr(reg.to_expr()), + StmtDeclaration::Instance(StmtInstance { + annotations: _, + instance, + }) => self.visit_canonical_expr(Expr::canonical(instance.to_expr())), + }; + Ok(()) + } + + fn visit_stmt(&mut self, stmt: &Stmt) -> Result<(), Self::Error> { + match stmt { + &Stmt::Connect(StmtConnect { + lhs, + rhs, + source_location: _, + }) => { + self.connect(lhs, rhs); + } + Stmt::Formal(_) | Stmt::If(_) | Stmt::Match(_) => stmt.default_visit(self)?, + Stmt::Declaration(stmt) => self.visit_stmt_declaration(stmt)?, + } + Ok(()) + } + + fn visit_module(&mut self, module: &Module) -> Result<(), Self::Error> { + let module = module.canonical().intern_sized(); + let visited = self.modules_visited.entry(module).or_insert(false); + if std::mem::replace(visited, true) { + return Ok(()); + } + let external = match module.body() { + ModuleBody::Normal(_) => false, + ModuleBody::Extern(_) => true, + }; + let is_root_module = self.root_module == module; + if external || is_root_module { + for module_io in module.module_io() { + let expr = module_io.module_io.to_expr(); + let mut connect_unknown = |is_lhs| { + if is_lhs { + self.connect(expr, ExprOrUnknown::Unknown(expr.ty())); + } else { + self.connect(ExprOrUnknown::Unknown(expr.ty()), expr); + } + }; + // all main/external module I/O can have non-zeroed padding + if external { + // outputs are unknown + connect_unknown(module_io.module_io.is_output()); + } + // note: the root module can be external, so we don't use `else if` here + if is_root_module { + // inputs are unknown + connect_unknown(module_io.module_io.is_input()); + } + } + } + module.default_visit(self) + } +} + +impl Folder for State { + type Error = Infallible; + fn fold_structural_eq(&mut self, v: StructuralEq) -> Result { + let lhs_flags = *self.expr_flags.find_mut(&Expr::expr_enum(v.lhs())); + let rhs_flags = *self.expr_flags.find_mut(&Expr::expr_enum(v.rhs())); + let inputs_assume_padding_is_zeroed = + lhs_flags.assume_padding_is_zeroed() & rhs_flags.assume_padding_is_zeroed(); + let new_lhs = v.lhs().fold(self)?; + let new_rhs = v.rhs().fold(self)?; + let StructuralEqFlags { + assume_padding_is_zeroed: orig_assume_padding_is_zeroed, + } = v.flags(); + Ok(StructuralEq::with_flags( + new_lhs, + new_rhs, + StructuralEqFlags { + assume_padding_is_zeroed: inputs_assume_padding_is_zeroed + | orig_assume_padding_is_zeroed, + }, + )) + } +} + +pub fn deduce_structural_eq_flags(module: Interned>) -> Interned> { + deduce_structural_eq_flags_with_debug_tracing(module, false) +} + +pub fn deduce_structural_eq_flags_with_debug_tracing( + module: Interned>, + debug_trace: bool, +) -> Interned> { + static CACHE: std::sync::Mutex< + Option>, Interned>>>, + > = std::sync::Mutex::new(None); + let cache = CACHE.lock().expect("not poisoned"); + if let Some(retval) = cache.as_ref().and_then(|cache| cache.get(&module)) { + return *retval; + } + drop(cache); + // the algorithm proceeds in two stages: + // 1. Visitor for State: a fixed-point data-flow algorithm to determine what flags should be + // 2. Folder for State: transforming the StructuralEq operations to have the deduced flags + let mut state = State::new(module, debug_trace); + let mut loops = 0; + const LOOP_LIMIT: u32 = 10000; + loop { + loops += 1; + let Ok(()) = module.visit(&mut state); + if loops > LOOP_LIMIT { + panic!("deduce_structural_eq_flags: looped too many times! state:\n{state:#?}"); + } + let State { + root_module: _, + debug_trace: _, + any_changes, + expr_flags: _, + exprs_visited: expr_visited, + modules_visited: module_visited, + } = &mut state; + if !std::mem::replace(any_changes, false) { + break; + } + expr_visited.values_mut().for_each(|v| *v = false); + module_visited.values_mut().for_each(|v| *v = false); + } + if debug_trace { + indented_println!("{state:#?}"); + } + let Ok(retval) = module.fold(&mut state); + CACHE + .lock() + .expect("not poisoned") + .get_or_insert_default() + .extend([(module, retval), (retval, retval)]); + retval +} diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index 280701d..6c137ca 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -1,28 +1,26 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - array::{Array, ArrayType}, - bundle::{Bundle, BundleField, BundleType}, - enum_::{Enum, EnumType, EnumVariant}, + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, expr::{ - CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType, - ops::{self, EnumLiteral}, + ExprEnum, + ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags}, }, - hdl, - int::UInt, intern::{Intern, InternSlice, Interned, Memoize}, - memory::{DynPortType, Mem, MemPort}, + memory::{DynPortType, MemPort}, module::{ - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, - transform::visit::{Fold, Folder}, + Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, + transform::{ + deduce_structural_eq_flags::deduce_structural_eq_flags, + visit::{Fold, Folder}, + }, }, - source_location::SourceLocation, - ty::{CanonicalType, TraceAsString, Type}, + prelude::*, util::HashMap, - wire::Wire, }; -use core::fmt; use serde::{Deserialize, Serialize}; +use std::fmt; #[derive(Debug)] pub enum SimplifyEnumsError { @@ -97,6 +95,7 @@ enum EnumTypeState { struct ModuleState { module_name: NameId, expr_cache: HashMap, + source_location: SourceLocation, } impl ModuleState { @@ -110,6 +109,45 @@ struct State { replacement_mem_ports: HashMap, Wire>, kind: SimplifyEnumsKind, module_state_stack: Vec, + new_prefix_stmts_for_block: Vec, + new_suffix_stmts_for_block: Vec, +} + +struct BlockScope<'a> { + state: &'a mut State, + parent_new_prefix_stmts_for_block: Vec, + parent_new_suffix_stmts_for_block: Vec, +} + +impl<'a> BlockScope<'a> { + fn new( + state: &'a mut State, + new_prefix_stmts_for_block: Vec, + new_suffix_stmts_for_block: Vec, + ) -> Self { + let parent_new_prefix_stmts_for_block = std::mem::replace( + &mut state.new_prefix_stmts_for_block, + new_prefix_stmts_for_block, + ); + let parent_new_suffix_stmts_for_block = std::mem::replace( + &mut state.new_suffix_stmts_for_block, + new_suffix_stmts_for_block, + ); + Self { + state, + parent_new_prefix_stmts_for_block, + parent_new_suffix_stmts_for_block, + } + } +} + +impl Drop for BlockScope<'_> { + fn drop(&mut self) { + self.state.new_prefix_stmts_for_block = + std::mem::take(&mut self.parent_new_prefix_stmts_for_block); + self.state.new_suffix_stmts_for_block = + std::mem::take(&mut self.parent_new_suffix_stmts_for_block); + } } impl State { @@ -549,6 +587,185 @@ impl State { | CanonicalType::DynSimOnly(_) => unreachable!(), } } + fn handle_enum_structural_eq( + &mut self, + unfolded_ty: Enum, + folded_lhs: Expr, + folded_rhs: Expr, + flags: StructuralEqFlags, + ) -> Result, 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::>::from_canonical(folded_lhs).tag), + Expr::canonical(Expr::>::from_canonical(folded_rhs).tag), + StructuralEqFlags { + assume_padding_is_zeroed: true, + }, + ) + .to_expr(), + EnumTypeState::TagUIntAndBody(_) => { + let lhs = Expr::>::from_canonical(folded_lhs).tag; + let rhs = Expr::>::from_canonical(folded_rhs).tag; + lhs.cmp_eq(rhs) + } + EnumTypeState::UInt(_) => { + let lhs_int_tag_expr = Expr::::from_canonical(folded_lhs) + [..unfolded_ty.discriminant_bit_width()]; + let rhs_int_tag_expr = Expr::::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, + folded_rhs: Expr, + flags: StructuralEqFlags, + ) -> Result, 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::::from_canonical(folded_lhs), + *Expr::::from_canonical(folded_rhs), + flags, + ), + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => unreachable!("doesn't contain any enum types"), + } + } } fn connect_port( @@ -677,6 +894,7 @@ impl Folder for State { self.module_state_stack.push(ModuleState { module_name: v.name_id(), expr_cache: HashMap::default(), + source_location: v.source_location(), }); let retval = Fold::default_fold(v, self); self.module_state_stack.pop(); @@ -710,6 +928,18 @@ impl Folder for State { op.variant_index(), )?) } + ExprEnum::StructuralEq(op) => { + let ty = op.lhs().ty(); + assert_eq!(ty, op.rhs().ty()); + let folded_lhs = Expr::canonical(op.lhs()).fold(self)?; + let folded_rhs = Expr::canonical(op.rhs()).fold(self)?; + *Expr::expr_enum(self.handle_structural_eq( + ty, + folded_lhs, + folded_rhs, + op.flags(), + )?) + } ExprEnum::MemPort(mem_port) => { if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) { ExprEnum::Wire(wire) @@ -837,11 +1067,13 @@ impl Folder for State { } fn fold_block(&mut self, block: Block) -> Result { + let block_scope = BlockScope::new(self, vec![], vec![]); + let this = &mut *block_scope.state; let mut memories = vec![]; let mut stmts = vec![]; for memory in block.memories { let old_element_ty = memory.array_type().element(); - let new_element_ty = memory.array_type().element().fold(self)?; + let new_element_ty = memory.array_type().element().fold(this)?; if new_element_ty != old_element_ty { let mut new_ports = vec![]; for port in memory.ports() { @@ -867,7 +1099,7 @@ impl Folder for State { continue; } let wire = Wire::new_unchecked( - self.module_state_stack + this.module_state_stack .last_mut() .unwrap() .gen_name(&format!( @@ -891,7 +1123,7 @@ impl Folder for State { Expr::canonical(wire.to_expr()), port.source_location(), ); - self.replacement_mem_ports.insert(port, wire.canonical()); + this.replacement_mem_ports.insert(port, wire.canonical()); } memories.push(Mem::new_unchecked( memory.scoped_name(), @@ -906,10 +1138,12 @@ impl Folder for State { memory.mem_annotations(), )); } else { - memories.push(memory.fold(self)?); + memories.push(memory.fold(this)?); } } - stmts.extend_from_slice(&block.stmts.fold(self)?); + stmts.extend_from_slice(&block.stmts.fold(this)?); + stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..)); + stmts.extend_from_slice(&this.new_suffix_stmts_for_block); Ok(Block { memories: Intern::intern_owned(memories), stmts: Intern::intern_owned(stmts), @@ -1031,10 +1265,13 @@ pub fn simplify_enums( module: Interned>, kind: SimplifyEnumsKind, ) -> Result>, SimplifyEnumsError> { + let module = deduce_structural_eq_flags(module); module.fold(&mut State { enum_types: HashMap::default(), replacement_mem_ports: HashMap::default(), kind, module_state_stack: vec![], + new_prefix_stmts_for_block: vec![], + new_suffix_stmts_for_block: vec![], }) } diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index ba85817..1552eab 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -384,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst { } impl HdlPartialEqImpl for PhantomConst { + const TRY_STRUCTURAL_EQ: bool = true; + #[track_caller] fn cmp_value_eq( lhs: Self, diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index c3c47fd..d82a540 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -3145,6 +3145,144 @@ impl Compiler { insns }) } + fn compile_structural_eq( + &mut self, + instantiated_module_or_global: InstantiatedModuleOrGlobal, + expr: ops::StructuralEq, + ) -> CompiledExpr { + if expr.flags().assume_padding_is_zeroed { + return self.compile_expr( + instantiated_module_or_global, + Expr::canonical(expr.lhs().cast_to_bits().cmp_eq(expr.rhs().cast_to_bits())), + ); + } + let source_location = instantiated_module_or_global.leaf_module_source_location(); + match expr.lhs().ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) => self.compile_expr( + instantiated_module_or_global, + Expr::canonical(expr.lhs().cast_to_bits().cmp_eq(expr.rhs().cast_to_bits())), + ), + CanonicalType::Array(_) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_expr( + instantiated_module_or_global, + Expr::canonical( + lhs.into_iter() + .zip(rhs) + .map(|(l, r)| { + ops::StructuralEq::with_flags(l, r, expr.flags()).to_expr() + }) + .reduce(|a, b| a & b) + .unwrap_or_else(|| true.to_expr()), + ), + ) + } + CanonicalType::Enum(ty) => { + let lhs = self.compile_expr(instantiated_module_or_global, expr.lhs()); + let lhs = self + .compiled_expr_to_value(lhs, source_location) + .map_ty(Enum::from_canonical); + let rhs = self.compile_expr(instantiated_module_or_global, expr.rhs()); + let rhs = self + .compiled_expr_to_value(rhs, source_location) + .map_ty(Enum::from_canonical); + let lhs_discriminant = self.compile_enum_discriminant(lhs, source_location); + let rhs_discriminant = self.compile_enum_discriminant(rhs, source_location); + let retval = self.simple_nary_big_expr( + instantiated_module_or_global, + Bool.canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: BigInt::ZERO.intern_sized(), + }] + }, + ); + for variant_index in 0..ty.variants().len() { + let variant_eq = self.compile_structural_eq( + instantiated_module_or_global, + ops::StructuralEq::with_flags( + ops::VariantAccess::new_by_index( + Expr::from_canonical(expr.lhs()), + variant_index, + ) + .to_expr(), + ops::VariantAccess::new_by_index( + Expr::from_canonical(expr.rhs()), + variant_index, + ) + .to_expr(), + expr.flags(), + ), + ); + let variant_eq = self.compiled_expr_to_value(variant_eq, source_location); + self.compile_simple_connect( + [ + Cond { + body: CondBody::MatchArm { + discriminant: lhs_discriminant, + variant_index, + }, + source_location, + }, + Cond { + body: CondBody::MatchArm { + discriminant: rhs_discriminant, + variant_index, + }, + source_location, + }, + ] + .intern_slice(), + retval.into(), + variant_eq, + source_location, + ); + } + retval.into() + } + CanonicalType::Bundle(ty) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_expr( + instantiated_module_or_global, + Expr::canonical( + (0..ty.fields().len()) + .map(|field_index| { + ops::StructuralEq::with_flags( + ops::FieldAccess::new_by_index(lhs, field_index).to_expr(), + ops::FieldAccess::new_by_index(rhs, field_index).to_expr(), + expr.flags(), + ) + .to_expr() + }) + .reduce(|a, b| a & b) + .unwrap_or_else(|| true.to_expr()), + ), + ) + } + CanonicalType::DynSimOnly(_) => { + unreachable!("StructuralEq is known to not have SimOnly in its inputs' types") + } + CanonicalType::TraceAsString(_) => { + let lhs = Expr::::from_canonical(expr.lhs()); + let rhs = Expr::::from_canonical(expr.rhs()); + self.compile_structural_eq( + instantiated_module_or_global, + ops::StructuralEq::with_flags(*lhs, *rhs, expr.flags()), + ) + } + } + } fn compile_expr( &mut self, instantiated_module_or_global: impl Into, @@ -3974,6 +4112,9 @@ impl Compiler { .compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg())) .map_ty(TraceAsString::from_canonical) .inner(), + ExprEnum::StructuralEq(expr) => { + self.compile_structural_eq(instantiated_module_or_global, expr) + } ExprEnum::ModuleIO(expr) => self .compile_value(TargetInInstantiatedModuleOrGlobal::from_target( instantiated_module_or_global, diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index 24bc1ef..dd47633 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -1508,6 +1508,8 @@ impl ToSimValue for SimOnlyValue { } impl HdlPartialEqImpl for DynSimOnly { + const TRY_STRUCTURAL_EQ: bool = false; + #[track_caller] fn cmp_value_eq( _lhs: Self, @@ -1527,6 +1529,8 @@ impl HdlPartialEqImpl for DynSimOnly { impl, R: SimOnlyValueTrait> HdlPartialEqImpl> for SimOnly { + const TRY_STRUCTURAL_EQ: bool = false; + #[track_caller] fn cmp_value_eq( _lhs: Self, diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index 843aedb..6505742 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -354,6 +354,39 @@ impl CanonicalType { } MyMemoize.get_owned((self, other)) } + pub fn contains_sim_only(self) -> bool { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize; + impl Memoize for MyMemoize { + type Input = CanonicalType; + type InputOwned = CanonicalType; + type Output = bool; + + fn inner(self, input: &Self::Input) -> Self::Output { + match input { + CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => { + false + } + CanonicalType::Array(ty) => ty.element().contains_sim_only(), + CanonicalType::Enum(ty) => ty + .variants() + .iter() + .any(|v| v.ty.is_some_and(CanonicalType::contains_sim_only)), + CanonicalType::Bundle(ty) => { + ty.fields().iter().any(|v| v.ty.contains_sim_only()) + } + CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) => false, + CanonicalType::DynSimOnly(_) => true, + CanonicalType::TraceAsString(ty) => ty.inner_ty().contains_sim_only(), + } + } + } + MyMemoize.get_owned(self) + } } pub trait MatchVariantAndInactiveScope: Sized { @@ -1882,6 +1915,8 @@ fn trace_as_string_cow_into_inner_value( } impl, U: Type> HdlPartialEqImpl> for TraceAsString { + const TRY_STRUCTURAL_EQ: bool = >::TRY_STRUCTURAL_EQ; + #[track_caller] fn cmp_value_eq( lhs: Self, diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 6845d3c..0e6723e 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -16,8 +16,8 @@ pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher; #[cfg(not(feature = "unstable-test-hasher"))] pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder; -pub(crate) type HashMap = hashbrown::HashMap; -pub(crate) type HashSet = hashbrown::HashSet; +pub(crate) type HashMap = hashbrown::HashMap; +pub(crate) type HashSet = hashbrown::HashSet; #[doc(inline)] pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool}; @@ -43,7 +43,11 @@ pub use misc::{ }; pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice}; +pub mod bool_fixed_point_solver; +pub(crate) mod indented_print; pub mod job_server; +pub mod map_trait; pub mod prefix_sum; pub mod ready_valid; pub(crate) mod serde_by_id; +pub mod union_find_map; diff --git a/crates/fayalite/src/util/bool_fixed_point_solver.rs b/crates/fayalite/src/util/bool_fixed_point_solver.rs new file mode 100644 index 0000000..91119e9 --- /dev/null +++ b/crates/fayalite/src/util/bool_fixed_point_solver.rs @@ -0,0 +1,711 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use petgraph::unionfind::UnionFind; +use std::{collections::BTreeSet, fmt}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Variable(usize); + +impl Variable { + pub fn index(self) -> usize { + self.0 + } +} + +impl fmt::Debug for Variable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for Variable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "v{}", self.0) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Constraint { + /// `variable` is constrained to be [`!solver.unconstrained_variables_value()`](BoolFixedPointSolver::unconstrained_variables_value()) + MaximallyConstrained { variable: Variable }, + /// the constraint is `dest == src` + Equal { dest: Variable, src: Variable }, + /// the constraint is `dest == dest & src` + And { dest: Variable, src: Variable }, + /// the constraint is `dest == dest | src` + Or { dest: Variable, src: Variable }, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// the constraint is `dest == dest & src` +struct AndConstraint { + dest: Variable, + src: Variable, +} + +impl AndConstraint { + fn from_or_constraint(or_constraint_dest: Variable, or_constraint_src: Variable) -> Self { + // `a == a | b` is equivalent to `b == b & a` + Self { + dest: or_constraint_src, + src: or_constraint_dest, + } + } +} + +impl fmt::Debug for AndConstraint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { dest, src } = *self; + write!(f, "{dest} == {dest} & {src}") + } +} + +#[derive(Clone)] +pub struct BoolFixedPointSolver { + variables_union_find: UnionFind, + variables_value: Vec, + maximally_constrained: Vec, + unconstrained_variables_value: bool, + solved: bool, + and_constraints: BTreeSet, +} + +impl fmt::Debug for BoolFixedPointSolver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + variables_union_find, + variables_value, + maximally_constrained, + unconstrained_variables_value, + solved, + and_constraints, + } = self; + f.debug_struct("BoolFixedPointSolver") + .field( + "variables_union_find", + &fmt::from_fn(|f| { + f.debug_map() + .entries( + (0..variables_union_find.len()) + .map(|i| (Variable(i), Variable(variables_union_find.find(i)))), + ) + .finish() + }), + ) + .field( + "variables_value", + &fmt::from_fn(|f| { + let mut debug_map = f.debug_map(); + for (i, v) in variables_value.iter().enumerate() { + if variables_union_find.find(i) == i { + debug_map.entry(&Variable(i), v); + } + } + debug_map.finish() + }), + ) + .field( + "maximally_constrained", + &fmt::from_fn(|f| { + let mut debug_map = f.debug_map(); + for (i, v) in maximally_constrained.iter().enumerate() { + if variables_union_find.find(i) == i { + debug_map.entry(&Variable(i), v); + } + } + debug_map.finish() + }), + ) + .field( + "unconstrained_variables_value", + unconstrained_variables_value, + ) + .field("solved", solved) + .field("and_constraints", and_constraints) + .finish() + } +} + +impl BoolFixedPointSolver { + pub const fn new(unconstrained_variables_value: bool) -> Self { + Self { + variables_union_find: UnionFind::new_empty(), + variables_value: Vec::new(), + maximally_constrained: Vec::new(), + unconstrained_variables_value, + solved: false, + and_constraints: BTreeSet::new(), + } + } + pub fn unconstrained_variables_value(&self) -> bool { + self.unconstrained_variables_value + } + pub fn new_variable(&mut self) -> Variable { + let index = self.variables_union_find.new_set(); + self.variables_value + .push(self.unconstrained_variables_value); + self.maximally_constrained.push(false); + self.solved = false; + Variable(index) + } + pub fn variable_count(&self) -> usize { + self.variables_union_find.len() + } + #[track_caller] + fn assert_variable_in_range(&self, variable: Variable) { + if variable.0 >= self.variable_count() { + panic!("invalid variable {variable:?}"); + } + } + #[track_caller] + pub fn add_constraint(&mut self, constraint: Constraint) { + self.solved = false; + match constraint { + Constraint::MaximallyConstrained { variable } => { + self.assert_variable_in_range(variable); + self.maximally_constrained[self.variables_union_find.find_mut(variable.0)] = true; + return; + } + Constraint::Equal { dest, src } => { + self.assert_variable_in_range(dest); + self.assert_variable_in_range(src); + let maximally_constrained = self.maximally_constrained + [self.variables_union_find.find_mut(dest.0)] + | self.maximally_constrained[self.variables_union_find.find_mut(src.0)]; + self.variables_union_find.union(dest.0, src.0); + let merged_index = self.variables_union_find.find_mut(dest.0); + self.maximally_constrained[merged_index] = maximally_constrained; + } + Constraint::And { dest, src } => { + self.assert_variable_in_range(src); + self.assert_variable_in_range(dest); + if src != dest { + self.and_constraints.insert(AndConstraint { dest, src }); + } + } + Constraint::Or { dest, src } => { + self.assert_variable_in_range(src); + self.assert_variable_in_range(dest); + if src != dest { + self.and_constraints + .insert(AndConstraint::from_or_constraint(dest, src)); + } + } + } + } + pub fn solve(&mut self) { + for (value, maximally_constrained) in self + .variables_value + .iter_mut() + .zip(&self.maximally_constrained) + { + *value = self.unconstrained_variables_value ^ *maximally_constrained; + } + let mut variables_to_constraints_map: Vec> = + vec![Vec::new(); self.variable_count()]; + for &AndConstraint { mut dest, mut src } in &self.and_constraints { + dest.0 = self.variables_union_find.find_mut(dest.0); + src.0 = self.variables_union_find.find_mut(src.0); + if dest == src { + continue; + } + let constraint = AndConstraint { dest, src }; + variables_to_constraints_map[dest.0].push(constraint); + variables_to_constraints_map[src.0].push(constraint); + } + let mut worklist: Vec = (0..self.variable_count()) + .filter(|&index| self.variables_union_find.find_mut(index) == index) + .map(Variable) + .collect(); + while let Some(variable) = worklist.pop() { + for &AndConstraint { dest, src } in &variables_to_constraints_map[variable.0] { + let dest_value = self.variables_value[dest.0]; + let src_value = self.variables_value[src.0]; + // equivalent to `dest_value != dest_value & src_value`: + let is_unsatisfied = dest_value && !src_value; + if is_unsatisfied { + if self.unconstrained_variables_value { + self.variables_value[dest.0] = false; + worklist.push(dest); + } else { + self.variables_value[src.0] = true; + worklist.push(src); + } + } + } + } + self.solved = true; + } + #[track_caller] + pub fn value(&mut self, variable: Variable) -> bool { + #[cold] + fn solve_cold(this: &mut BoolFixedPointSolver) { + this.solve(); + } + self.assert_variable_in_range(variable); + if !self.solved { + solve_cold(self); + } + self.variables_value[self.variables_union_find.find_mut(variable.0)] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::num::NonZero; + + struct TestCase<'a, C, Vars, Vals> { + variable_count: usize, + expected_values: Option<&'a [bool]>, + constraints: C, + variables: Vars, + values: Vals, + solver: BoolFixedPointSolver, + } + + impl<'a, C: FnOnce(&[Variable]) -> I, I: IntoIterator> TestCase<'a, C, (), ()> { + fn new_expected( + unconstrained_variables_value: bool, + expected_values: &'a [bool], + constraints: C, + ) -> Self { + Self { + variable_count: expected_values.len(), + expected_values: Some(expected_values), + constraints, + variables: (), + values: (), + solver: BoolFixedPointSolver::new(unconstrained_variables_value), + } + } + #[track_caller] + fn get_constraints_and_variables( + self, + ) -> TestCase<'a, Vec, Vec, [bool; 0]> { + let Self { + variable_count, + expected_values, + constraints, + variables: (), + values: (), + mut solver, + } = self; + assert_eq!( + expected_values.map_or(variable_count, |v| v.len()), + variable_count, + ); + let variables = Vec::from_iter((0..variable_count).map(|_| solver.new_variable())); + let constraints = Vec::from_iter(constraints(&variables)); + TestCase { + variable_count, + expected_values, + constraints, + variables, + values: [], + solver, + } + } + } + + impl<'a> TestCase<'a, Vec, Vec, [bool; 0]> { + #[track_caller] + fn add_and_check_constraints(&mut self) { + if let Some(expected_values) = self.expected_values { + self.check_constraints("expected values", expected_values); + } + for &constraint in &self.constraints { + self.solver.add_constraint(constraint); + } + } + #[track_caller] + fn get_values(self) -> TestCase<'a, Vec, Vec, Vec> { + let Self { + variable_count, + expected_values, + constraints, + variables, + values: [], + mut solver, + } = self; + let values = Vec::from_iter(variables.iter().map(|&v| solver.value(v))); + TestCase { + variable_count, + expected_values, + constraints, + variables, + values, + solver, + } + } + } + + impl<'a> TestCase<'a, Vec, Vec, Vec> { + #[track_caller] + fn check_values(&self) { + let Self { + variable_count: _, + expected_values, + constraints: _, + variables, + values, + solver: _, + } = self; + if let Some(expected_values) = expected_values { + for ((&expected_value, &variable), &value) in + expected_values.iter().zip(variables).zip(values) + { + if expected_value != value { + self.error(format_args!( + "solver output for {variable} of {value:?} doesn't \ + match expected value of {expected_value:?}", + )); + } + } + } + self.check_constraints("solved values", values); + } + } + + impl<'a, Vals: AsRef<[bool]>> TestCase<'a, Vec, Vec, Vals> { + #[track_caller] + fn check_constraints(&self, values_name: &str, values: &[bool]) { + let unconstrained_variables_value = self.solver.unconstrained_variables_value(); + let v = |variable: Variable| values[variable.index()]; + for &constraint in &self.constraints { + let satisfied = match constraint { + Constraint::MaximallyConstrained { variable } => { + v(variable) != unconstrained_variables_value + } + Constraint::Equal { dest, src } => v(dest) == v(src), + Constraint::And { dest, src } => v(dest) == v(dest) & v(src), + Constraint::Or { dest, src } => v(dest) == v(dest) | v(src), + }; + if !satisfied { + self.error(format_args!( + "{values_name} don't satisfy constraint: {constraint:#?}" + )); + } + } + } + #[track_caller] + fn error(&self, msg: fmt::Arguments<'_>) -> ! { + let Self { + variable_count, + expected_values, + ref constraints, + ref variables, + ref values, + ref solver, + } = *self; + let values = values.as_ref(); + panic!( + "{msg}\n\ + values={values:#?}\n\ + constraints={constraints:#?}\n\ + solver={solver:#?}", + values = fmt::from_fn(|f| { + let mut debug_map = f.debug_map(); + for i in 0..variable_count { + debug_map.key(&variables[i]); + if let Some(value) = values.get(i) { + if let Some(expected_values) = expected_values { + debug_map.value(&format_args!( + "{value:?} (expected: {:?})", + expected_values[i], + )); + } else { + debug_map.value(value); + } + } else if let Some(expected_values) = expected_values { + debug_map.value(&format_args!("(expected: {:?})", expected_values[i])); + } else { + debug_map.value(&format_args!("None")); + } + } + debug_map.finish() + }), + ); + } + } + + #[track_caller] + fn test_case>( + test_case: TestCase<'_, impl FnOnce(&[Variable]) -> I, (), ()>, + ) { + let mut test_case = test_case.get_constraints_and_variables(); + test_case.add_and_check_constraints(); + let test_case = test_case.get_values(); + test_case.check_values(); + } + + #[test] + fn test_bool_fixed_point_solver_simple() { + test_case(TestCase::new_expected(false, &[], |_| [])); + test_case(TestCase::new_expected(true, &[], |_| [])); + test_case(TestCase::new_expected(false, &[false], |_| [])); + test_case(TestCase::new_expected(true, &[true], |_| [])); + test_case(TestCase::new_expected(false, &[true], |v| { + [Constraint::MaximallyConstrained { variable: v[0] }] + })); + test_case(TestCase::new_expected(true, &[false], |v| { + [Constraint::MaximallyConstrained { variable: v[0] }] + })); + test_case(TestCase::new_expected(false, &[true, true], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Equal { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(true, &[false, false], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Equal { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(false, &[true, false], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::And { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(true, &[false, false], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::And { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(false, &[true, true], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::And { + dest: v[0], + src: v[1], + }, + ] + })); + test_case(TestCase::new_expected(true, &[false, true], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::And { + dest: v[0], + src: v[1], + }, + ] + })); + test_case(TestCase::new_expected(false, &[true, true], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Or { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(true, &[false, true], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Or { + dest: v[1], + src: v[0], + }, + ] + })); + test_case(TestCase::new_expected(false, &[true, false], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Or { + dest: v[0], + src: v[1], + }, + ] + })); + test_case(TestCase::new_expected(true, &[false, false], |v| { + [ + Constraint::MaximallyConstrained { variable: v[0] }, + Constraint::Or { + dest: v[0], + src: v[1], + }, + ] + })); + } + + #[derive(Debug)] + struct Rng { + state: u64, + } + + impl Rng { + fn new(test_case_index: u32) -> Self { + Self { + state: (test_case_index as u64) << 32, + } + } + fn next_u64(&mut self) -> u64 { + self.state += 1; + // 4 random primes and 4 random rotate amounts + self.state + .wrapping_mul(0xA3C7_8807_EA6D_A4F9) + .rotate_left(43) + .wrapping_mul(0x1CCA_797A_6BF8_8C63) + .rotate_left(8) + .wrapping_mul(0xCC50_AA59_7C41_946F) + .rotate_left(12) + .wrapping_mul(0xFB2A_0137_F878_C4B5) + .rotate_left(58) + } + #[track_caller] + fn next_u64_in_range(&mut self, range: std::ops::Range) -> u64 { + let Some(len) = range.end.checked_sub(range.start).and_then(NonZero::new) else { + panic!("empty range: {range:?}"); + }; + let max_quotient = u64::MAX / len; + loop { + let next_u64 = self.next_u64(); + let quotient = next_u64 / len; + let remainder = next_u64 % len; + if quotient < max_quotient { + return remainder + range.start; + } + } + } + #[track_caller] + fn next_usize_in_range(&mut self, range: std::ops::Range) -> usize { + self.next_u64_in_range(range.start as u64..range.end as u64) as usize + } + #[track_caller] + fn next_from_slice<'a, T>(&mut self, slice: &'a [T]) -> &'a T { + assert!(!slice.is_empty()); + &slice[self.next_usize_in_range(0..slice.len())] + } + fn next_bool(&mut self) -> bool { + (self.next_u64() & 1) != 0 + } + } + + #[track_caller] + fn test_bool_fixed_point_solver_random_case(test_case_index: u32) { + println!("test_bool_fixed_point_solver_random_case({test_case_index})"); + let mut rng = Rng::new(test_case_index); + // bias towards smaller problems to make them easier to debug + let variable_count = rng + .next_u64_in_range(1..1_000_000) + .pow(2) + .div_ceil(1_000_000_000) as usize; + let constraint_count = + rng.next_usize_in_range(0..(variable_count * variable_count).clamp(0, 10000)); + let solver = BoolFixedPointSolver::new(rng.next_bool()); + test_case(TestCase { + variable_count, + expected_values: None, + constraints: |variables: &[Variable]| { + Vec::from_iter( + (0..constraint_count).map(|_| match rng.next_usize_in_range(0..4) { + 0 => Constraint::MaximallyConstrained { + variable: *rng.next_from_slice(variables), + }, + 1 => Constraint::Equal { + dest: *rng.next_from_slice(variables), + src: *rng.next_from_slice(variables), + }, + 2 => Constraint::And { + dest: *rng.next_from_slice(variables), + src: *rng.next_from_slice(variables), + }, + 3 => Constraint::Or { + dest: *rng.next_from_slice(variables), + src: *rng.next_from_slice(variables), + }, + 4.. => unreachable!(), + }), + ) + }, + variables: (), + values: (), + solver, + }); + } + + const CASES_FULL_RANGE: std::ops::Range = 0..100_000; + + fn mul_div(v: u32, factor: u32, divisor: u32) -> u32 { + ((v as u64 * factor as u64) / divisor as u64) as u32 + } + + #[track_caller] + fn test_bool_fixed_point_solver_random_cases(split_index: u32) { + assert!(split_index < CASES_SPLIT_COUNT); + let full_range_len = CASES_FULL_RANGE.end - CASES_FULL_RANGE.start; + let start = mul_div(split_index, full_range_len, CASES_SPLIT_COUNT); + let end = mul_div(split_index + 1, full_range_len, CASES_SPLIT_COUNT); + for test_case_index in start..end { + test_bool_fixed_point_solver_random_case(test_case_index) + } + } + + const CASES_SPLIT_COUNT: u32 = 10; + + #[test] + fn test_bool_fixed_point_solver_random_cases_0() { + test_bool_fixed_point_solver_random_cases(0); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_1() { + test_bool_fixed_point_solver_random_cases(1); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_2() { + test_bool_fixed_point_solver_random_cases(2); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_3() { + test_bool_fixed_point_solver_random_cases(3); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_4() { + test_bool_fixed_point_solver_random_cases(4); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_5() { + test_bool_fixed_point_solver_random_cases(5); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_6() { + test_bool_fixed_point_solver_random_cases(6); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_7() { + test_bool_fixed_point_solver_random_cases(7); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_8() { + test_bool_fixed_point_solver_random_cases(8); + } + + #[test] + fn test_bool_fixed_point_solver_random_cases_9() { + test_bool_fixed_point_solver_random_cases(9); + } +} diff --git a/crates/fayalite/src/util/indented_print.rs b/crates/fayalite/src/util/indented_print.rs new file mode 100644 index 0000000..7243578 --- /dev/null +++ b/crates/fayalite/src/util/indented_print.rs @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use std::{ + fmt::{self, Write as _}, + marker::PhantomData, +}; + +struct IndentState { + indent: usize, + need_indent: bool, + buf: String, +} + +thread_local! { + static INDENT_STATE: std::cell::RefCell = const { + std::cell::RefCell::new(IndentState { + indent: 0, + need_indent: true, + buf: String::new(), + }) + }; +} + +struct IndentedOut; + +impl fmt::Write for IndentedOut { + fn write_str(&mut self, s: &str) -> fmt::Result { + INDENT_STATE.with_borrow_mut(|state| { + let IndentState { + indent, + need_indent, + buf, + } = state; + buf.clear(); + for ch in s.chars() { + if ch == '\n' { + *need_indent = true; + } else { + if *need_indent { + *need_indent = false; + for _ in 0..*indent { + buf.push_str(" "); + } + } + } + buf.push(ch) + } + std::print!("{buf}"); + }); + Ok(()) + } +} + +#[allow(unused)] +pub(crate) struct PushIndent(PhantomData<*const ()>); + +impl Drop for PushIndent { + fn drop(&mut self) { + let _ = INDENT_STATE.try_with(|state| state.borrow_mut().indent -= 1); + } +} + +impl PushIndent { + #[allow(unused)] + pub(crate) fn new() -> Self { + INDENT_STATE.with_borrow_mut(|state| state.indent += 1); + Self(PhantomData) + } +} + +#[allow(unused)] +pub(crate) fn indented_print_fmt(args: fmt::Arguments<'_>) { + if LN { + writeln!(IndentedOut, "{args}").expect("writing can't fail") + } else { + IndentedOut.write_fmt(args).expect("writing can't fail") + } +} + +#[allow(unused)] +macro_rules! indented_print { + ($($args:tt)*) => { + $crate::util::indented_print::indented_print_fmt::($crate::__std::format_args!($($args)*)) + }; +} + +#[allow(unused)] +pub(crate) use indented_print; + +#[allow(unused)] +macro_rules! indented_println { + ($($args:tt)*) => { + $crate::util::indented_print::indented_print_fmt::($crate::__std::format_args!($($args)*)) + }; +} + +#[allow(unused)] +pub(crate) use indented_println; + +#[allow(unused)] +macro_rules! indented_dbg { + ($expr:expr) => {{ + let v = $expr; + $crate::util::indented_print::indented_println!( + "[{}:{}:{}] {} = {v:#?}", + file!(), + line!(), + column!(), + stringify!($expr), + ); + v + }}; +} + +#[allow(unused)] +pub(crate) use indented_dbg; diff --git a/crates/fayalite/src/util/map_trait.rs b/crates/fayalite/src/util/map_trait.rs new file mode 100644 index 0000000..6fc065c --- /dev/null +++ b/crates/fayalite/src/util/map_trait.rs @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use std::fmt; + +pub enum Entry<'a, M: Map + 'a> { + Vacant(M::VacantEntry<'a>), + Occupied(M::OccupiedEntry<'a>), +} + +impl<'a, M: Map + 'a> Entry<'a, M> { + pub fn and_modify(mut self, f: F) -> Self { + if let Self::Occupied(entry) = &mut self { + f(entry.get_mut()); + } + self + } + pub fn insert_entry(self, v: M::Value) -> M::OccupiedEntry<'a> { + match self { + Self::Vacant(entry) => entry.insert_entry(v), + Self::Occupied(mut entry) => { + entry.insert(v); + entry + } + } + } + pub fn key(&self) -> &M::Key { + match self { + Self::Vacant(entry) => entry.key(), + Self::Occupied(entry) => entry.key(), + } + } + pub fn or_default(self) -> &'a mut M::Value + where + M::Value: Default, + { + self.or_insert_with(Default::default) + } + pub fn or_insert(self, v: M::Value) -> &'a mut M::Value { + match self { + Self::Vacant(entry) => entry.insert(v), + Self::Occupied(entry) => entry.into_mut(), + } + } + pub fn or_insert_with M::Value>(self, f: F) -> &'a mut M::Value { + match self { + Self::Vacant(entry) => entry.insert(f()), + Self::Occupied(entry) => entry.into_mut(), + } + } + pub fn or_insert_with_key M::Value>(self, f: F) -> &'a mut M::Value { + match self { + Self::Vacant(entry) => { + let v = f(entry.key()); + entry.insert(v) + } + Self::Occupied(entry) => entry.into_mut(), + } + } +} + +impl<'a, M: Map: fmt::Debug, VacantEntry<'a>: fmt::Debug> + 'a> fmt::Debug + for Entry<'a, M> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Vacant(v) => f.debug_tuple("Vacant").field(v).finish(), + Self::Occupied(v) => f.debug_tuple("Occupied").field(v).finish(), + } + } +} + +pub trait VacantEntry<'a>: Sized { + type Map: Map = Self> + 'a; + fn insert(self, v: ::Value) -> &'a mut ::Value; + fn insert_entry(self, v: ::Value) -> ::OccupiedEntry<'a>; + fn into_key(self) -> ::Key; + fn key(&self) -> &::Key; +} + +pub trait OccupiedEntry<'a>: Sized { + type Map: Map = Self> + 'a; + fn get(&self) -> &::Value; + fn get_mut(&mut self) -> &mut ::Value; + fn insert(&mut self, v: ::Value) -> ::Value; + fn into_mut(self) -> &'a mut ::Value; + fn key(&self) -> &::Key; + fn remove(self) -> ::Value; + fn remove_entry(self) -> (::Key, ::Value); +} + +pub trait Map: + Sized + + IntoIterator::Key, ::Value)> + + Extend<(::Key, ::Value)> + + FromIterator<(::Key, ::Value)> +{ + type Key; + type Value; + type IntoKeys: Iterator; + type IntoValues: Iterator; + type Iter<'a>: Iterator + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type IterMut<'a>: Iterator + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type Keys<'a>: Iterator + where + Self: 'a, + Self::Key: 'a; + type Values<'a>: Iterator + where + Self: 'a, + Self::Value: 'a; + type ValuesMut<'a>: Iterator + where + Self: 'a, + Self::Value: 'a; + type OccupiedEntry<'a>: OccupiedEntry<'a, Map = Self> + where + Self: 'a; + type VacantEntry<'a>: VacantEntry<'a, Map = Self> + where + Self: 'a; + fn clear(&mut self); + fn entry(&mut self, k: Self::Key) -> Entry<'_, Self>; + fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option; + fn into_keys(self) -> Self::IntoKeys; + fn into_values(self) -> Self::IntoValues; + fn is_empty(&self) -> bool; + fn iter(&self) -> Self::Iter<'_>; + fn iter_mut(&mut self) -> Self::IterMut<'_>; + fn keys(&self) -> Self::Keys<'_>; + fn len(&self) -> usize; + fn retain bool>(&mut self, f: F); + fn values(&self) -> Self::Values<'_>; + fn values_mut(&mut self) -> Self::ValuesMut<'_>; +} + +pub trait MapGet: Map { + fn contains_key(&self, k: &Q) -> bool; + fn get(&self, k: &Q) -> Option<&Self::Value>; + fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value>; + fn remove(&mut self, k: &Q) -> Option; + fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)>; +} + +mod hash_map { + use super::*; + use crate::util::HashMap; + use hashbrown::{Equivalent, hash_map}; + use std::hash::{BuildHasher, Hash}; + + impl Map for HashMap { + type Key = K; + type Value = V; + type IntoKeys = hash_map::IntoKeys; + type IntoValues = hash_map::IntoValues; + type Iter<'a> + = hash_map::Iter<'a, K, V> + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type IterMut<'a> + = hash_map::IterMut<'a, K, V> + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type Keys<'a> + = hash_map::Keys<'a, K, V> + where + Self: 'a, + Self::Key: 'a; + type Values<'a> + = hash_map::Values<'a, K, V> + where + Self: 'a, + Self::Value: 'a; + type ValuesMut<'a> + = hash_map::ValuesMut<'a, K, V> + where + Self: 'a, + Self::Value: 'a; + type OccupiedEntry<'a> + = hash_map::OccupiedEntry<'a, K, V, H> + where + Self: 'a; + type VacantEntry<'a> + = hash_map::VacantEntry<'a, K, V, H> + where + Self: 'a; + fn clear(&mut self) { + self.clear(); + } + fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> { + use hash_map::Entry::*; + match self.entry(k) { + Occupied(entry) => Entry::Occupied(entry), + Vacant(entry) => Entry::Vacant(entry), + } + } + fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option { + self.insert(k, v) + } + fn into_keys(self) -> Self::IntoKeys { + self.into_keys() + } + fn into_values(self) -> Self::IntoValues { + self.into_values() + } + fn is_empty(&self) -> bool { + self.is_empty() + } + fn iter(&self) -> Self::Iter<'_> { + self.iter() + } + fn iter_mut(&mut self) -> Self::IterMut<'_> { + self.iter_mut() + } + fn keys(&self) -> Self::Keys<'_> { + self.keys() + } + fn len(&self) -> usize { + self.len() + } + fn retain bool>(&mut self, f: F) { + self.retain(f); + } + fn values(&self) -> Self::Values<'_> { + self.values() + } + fn values_mut(&mut self) -> Self::ValuesMut<'_> { + self.values_mut() + } + } + + impl> MapGet + for HashMap + { + fn contains_key(&self, k: &Q) -> bool { + self.contains_key(k) + } + fn get(&self, k: &Q) -> Option<&Self::Value> { + self.get(k) + } + fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> { + self.get_mut(k) + } + fn remove(&mut self, k: &Q) -> Option { + self.remove(k) + } + fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> { + self.remove_entry(k) + } + } + + impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> VacantEntry<'a> + for hash_map::VacantEntry<'a, K, V, H> + { + type Map = HashMap; + fn insert(self, v: ::Value) -> &'a mut ::Value { + self.insert(v) + } + fn insert_entry( + self, + v: ::Value, + ) -> ::OccupiedEntry<'a> { + self.insert_entry(v) + } + fn into_key(self) -> ::Key { + self.into_key() + } + fn key(&self) -> &::Key { + self.key() + } + } + + impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> OccupiedEntry<'a> + for hash_map::OccupiedEntry<'a, K, V, H> + { + type Map = HashMap; + fn get(&self) -> &::Value { + self.get() + } + fn get_mut(&mut self) -> &mut ::Value { + self.get_mut() + } + fn insert(&mut self, v: ::Value) -> ::Value { + self.insert(v) + } + fn into_mut(self) -> &'a mut ::Value { + self.into_mut() + } + fn key(&self) -> &::Key { + self.key() + } + fn remove(self) -> ::Value { + self.remove() + } + fn remove_entry(self) -> (::Key, ::Value) { + self.remove_entry() + } + } +} + +mod btree_map { + use super::*; + use std::collections::{BTreeMap, btree_map}; + + impl Map for BTreeMap { + type Key = K; + type Value = V; + type IntoKeys = btree_map::IntoKeys; + type IntoValues = btree_map::IntoValues; + type Iter<'a> + = btree_map::Iter<'a, K, V> + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type IterMut<'a> + = btree_map::IterMut<'a, K, V> + where + Self: 'a, + Self::Key: 'a, + Self::Value: 'a; + type Keys<'a> + = btree_map::Keys<'a, K, V> + where + Self: 'a, + Self::Key: 'a; + type Values<'a> + = btree_map::Values<'a, K, V> + where + Self: 'a, + Self::Value: 'a; + type ValuesMut<'a> + = btree_map::ValuesMut<'a, K, V> + where + Self: 'a, + Self::Value: 'a; + type OccupiedEntry<'a> + = btree_map::OccupiedEntry<'a, K, V> + where + Self: 'a; + type VacantEntry<'a> + = btree_map::VacantEntry<'a, K, V> + where + Self: 'a; + fn clear(&mut self) { + self.clear(); + } + fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> { + use btree_map::Entry::*; + match self.entry(k) { + Occupied(entry) => Entry::Occupied(entry), + Vacant(entry) => Entry::Vacant(entry), + } + } + fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option { + self.insert(k, v) + } + fn into_keys(self) -> Self::IntoKeys { + self.into_keys() + } + fn into_values(self) -> Self::IntoValues { + self.into_values() + } + fn is_empty(&self) -> bool { + self.is_empty() + } + fn iter(&self) -> Self::Iter<'_> { + self.iter() + } + fn iter_mut(&mut self) -> Self::IterMut<'_> { + self.iter_mut() + } + fn keys(&self) -> Self::Keys<'_> { + self.keys() + } + fn len(&self) -> usize { + self.len() + } + fn retain bool>(&mut self, f: F) { + self.retain(f); + } + fn values(&self) -> Self::Values<'_> { + self.values() + } + fn values_mut(&mut self) -> Self::ValuesMut<'_> { + self.values_mut() + } + } + + impl, V, Q: ?Sized + Ord> MapGet for BTreeMap { + fn contains_key(&self, k: &Q) -> bool { + self.contains_key(k) + } + fn get(&self, k: &Q) -> Option<&Self::Value> { + self.get(k) + } + fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> { + self.get_mut(k) + } + fn remove(&mut self, k: &Q) -> Option { + self.remove(k) + } + fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> { + self.remove_entry(k) + } + } + + impl<'a, K: Ord, V> VacantEntry<'a> for btree_map::VacantEntry<'a, K, V> { + type Map = BTreeMap; + fn insert(self, v: ::Value) -> &'a mut ::Value { + self.insert(v) + } + fn insert_entry( + self, + v: ::Value, + ) -> ::OccupiedEntry<'a> { + self.insert_entry(v) + } + fn into_key(self) -> ::Key { + self.into_key() + } + fn key(&self) -> &::Key { + self.key() + } + } + + impl<'a, K: Ord, V> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> { + type Map = BTreeMap; + fn get(&self) -> &::Value { + self.get() + } + fn get_mut(&mut self) -> &mut ::Value { + self.get_mut() + } + fn insert(&mut self, v: ::Value) -> ::Value { + self.insert(v) + } + fn into_mut(self) -> &'a mut ::Value { + self.into_mut() + } + fn key(&self) -> &::Key { + self.key() + } + fn remove(self) -> ::Value { + self.remove() + } + fn remove_entry(self) -> (::Key, ::Value) { + self.remove_entry() + } + } +} diff --git a/crates/fayalite/src/util/union_find_map.rs b/crates/fayalite/src/util/union_find_map.rs new file mode 100644 index 0000000..d197a61 --- /dev/null +++ b/crates/fayalite/src/util/union_find_map.rs @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::util::{ + HashMap, + map_trait::{self, Map, MapGet, OccupiedEntry as _, VacantEntry as _}, +}; +use petgraph::unionfind::UnionFind; +use std::{collections::BTreeMap, fmt, marker::PhantomData}; + +pub struct UnionFindMap> { + uf: UnionFind, + keys_to_indexes: M, + values: Vec>, + _phantom: PhantomData, +} + +impl> fmt::Debug + for UnionFindMap +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut indexes_to_keys = vec![None; self.len()]; + for (k, &index) in self.keys_to_indexes.iter() { + indexes_to_keys[index] = Some(k); + } + let mut debug_map = f.debug_map(); + for (index, key) in indexes_to_keys.into_iter().enumerate() { + if let Some(key) = key { + debug_map.key(key); + } else { + debug_map.key(&fmt::from_fn(|f| { + f.write_str("<>") + })); + } + let set_index = self.uf.find(index); + debug_map.value(&fmt::from_fn(|f| { + write!(f, "@{set_index} ")?; + if set_index == index { + let Some(value) = &self.values[index] else { + unreachable!(); + }; + value.fmt(f) + } else { + Ok(()) + } + })); + } + debug_map.finish() + } +} + +impl> UnionFindMap { + /// returns the number of keys, not the number of sets/values + pub fn len(&self) -> usize { + self.values.len() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn capacity(&self) -> usize { + self.values.capacity() + } + #[track_caller] + pub fn equiv(&self, k1: &K1, k2: &K2) -> bool + where + M: MapGet + MapGet, + { + self.try_equiv(k1, k2).expect("key not found") + } + pub fn try_equiv(&self, k1: &K1, k2: &K2) -> Option + where + M: MapGet + MapGet, + { + let &index1 = self.keys_to_indexes.get(k1)?; + let &index2 = self.keys_to_indexes.get(k2)?; + Some(self.uf.equiv(index1, index2)) + } + #[track_caller] + pub fn find(&self, k: &Q) -> &V + where + M: MapGet, + { + self.try_find(k).expect("key not found") + } + pub fn try_find(&self, k: &Q) -> Option<&V> + where + M: MapGet, + { + let &index = self.keys_to_indexes.get(k)?; + self.values[self.uf.find(index)].as_ref() + } + #[track_caller] + pub fn find_mut(&mut self, k: &Q) -> &mut V + where + M: MapGet, + { + self.try_find_mut(k).expect("key not found") + } + pub fn try_find_mut(&mut self, k: &Q) -> Option<&mut V> + where + M: MapGet, + { + let &index = self.keys_to_indexes.get(k)?; + self.values[self.uf.find_mut(index)].as_mut() + } + /// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key + pub fn insert(&mut self, k: K, v: V) -> Option { + match self.entry(k) { + Entry::Vacant(entry) => { + entry.insert(v); + None + } + Entry::Occupied(mut entry) => Some(entry.insert(v)), + } + } + pub fn entry(&mut self, k: K) -> Entry<'_, K, V, M> { + match self.keys_to_indexes.entry(k) { + map_trait::Entry::Vacant(keys_to_indexes_entry) => Entry::Vacant(VacantEntry { + keys_to_indexes_entry, + uf: &mut self.uf, + values: &mut self.values, + }), + map_trait::Entry::Occupied(keys_to_indexes_entry) => { + let set_index = self.uf.find_mut(*keys_to_indexes_entry.get()); + Entry::Occupied(OccupiedEntry { + keys_to_indexes_entry, + set_index, + values: &mut self.values, + }) + } + } + } + /// Unify the two sets containing `k1` and `k2`. + /// If the sets were the same, returns `Some((false, value))`, + /// otherwise calling `merge` to merge their values and returning `Some((true, value))`. + /// Returns `None` if either of the keys weren't found. + pub fn try_union( + &mut self, + k1: &K1, + k2: &K2, + merge: F, + ) -> Option<(bool, &mut V)> + where + M: MapGet + MapGet, + F: FnOnce(&K1, V, &K2, V) -> V, + { + let &index1 = self.keys_to_indexes.get(k1)?; + let &index2 = self.keys_to_indexes.get(k2)?; + let index1 = self.uf.find_mut(index1); + let index2 = self.uf.find_mut(index2); + if index1 == index2 { + return Some((false, self.values[index1].as_mut()?)); + } + assert!(self.uf.union(index1, index2)); + let v1 = self.values[index1].take().expect("known to be Some"); + let v2 = self.values[index2].take().expect("known to be Some"); + let dest = &mut self.values[self.uf.find_mut(index1)]; + let dest = dest.insert(merge(k1, v1, k2, v2)); + Some((true, dest)) + } + /// Unify the two sets containing `k1` and `k2`. + /// If the sets were the same, returns `(false, value)`, + /// otherwise calling `merge` to merge their values and returning `(true, value)`. + /// panics if either of the keys weren't found. + #[track_caller] + pub fn union(&mut self, k1: &K1, k2: &K2, merge: F) -> (bool, &mut V) + where + M: MapGet + MapGet, + F: FnOnce(&K1, V, &K2, V) -> V, + { + self.try_union(k1, k2, merge).expect("key not found") + } +} + +impl UnionFindMap { + pub fn new() -> Self { + Self::with_hasher(Default::default()) + } + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, Default::default()) + } +} + +impl UnionFindMap> { + pub const fn new_btree() -> Self { + Self { + uf: UnionFind::new_empty(), + keys_to_indexes: BTreeMap::new(), + values: Vec::new(), + _phantom: PhantomData, + } + } +} + +impl UnionFindMap> { + pub const fn with_hasher(hash_builder: H) -> Self { + Self { + uf: UnionFind::new_empty(), + keys_to_indexes: HashMap::with_hasher(hash_builder), + values: Vec::new(), + _phantom: PhantomData, + } + } + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: H) -> Self { + Self { + uf: UnionFind::with_capacity(capacity), + keys_to_indexes: HashMap::with_capacity_and_hasher(capacity, hash_builder), + values: Vec::with_capacity(capacity), + _phantom: PhantomData, + } + } +} + +impl Default for UnionFindMap { + fn default() -> Self { + Self { + uf: UnionFind::new_empty(), + keys_to_indexes: M::default(), + values: Vec::new(), + _phantom: PhantomData, + } + } +} + +pub struct OccupiedEntry<'a, K, V, M: Map + 'a> { + keys_to_indexes_entry: M::OccupiedEntry<'a>, + set_index: usize, + values: &'a mut [Option], +} + +impl<'a, K, V, M: Map + 'a> OccupiedEntry<'a, K, V, M> { + pub fn get(&self) -> &V { + let Some(v) = &self.values[self.set_index] else { + unreachable!() + }; + v + } + pub fn get_mut(&mut self) -> &mut V { + let Some(v) = &mut self.values[self.set_index] else { + unreachable!() + }; + v + } + /// replaces the value for this set + pub fn insert(&mut self, v: V) -> V { + std::mem::replace(self.get_mut(), v) + } + pub fn into_mut(self) -> &'a mut V { + let Some(v) = &mut self.values[self.set_index] else { + unreachable!() + }; + v + } + pub fn key(&self) -> &K { + self.keys_to_indexes_entry.key() + } +} + +pub struct VacantEntry<'a, K, V, M: Map + 'a> { + keys_to_indexes_entry: M::VacantEntry<'a>, + uf: &'a mut UnionFind, + values: &'a mut Vec>, +} + +impl<'a, K, V, M: Map + 'a> VacantEntry<'a, K, V, M> { + /// inserts a new key as a new set + pub fn insert(self, v: V) -> &'a mut V { + self.insert_entry(v).into_mut() + } + /// inserts a new key as a new set + pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> { + let Self { + keys_to_indexes_entry, + uf, + values, + } = self; + let set_index = uf.new_set(); + values.push(Some(v)); + OccupiedEntry { + keys_to_indexes_entry: keys_to_indexes_entry.insert_entry(set_index), + set_index, + values, + } + } + pub fn into_key(self) -> K { + self.keys_to_indexes_entry.into_key() + } + pub fn key(&self) -> &K { + self.keys_to_indexes_entry.key() + } +} + +pub enum Entry<'a, K, V, M: Map + 'a> { + Vacant(VacantEntry<'a, K, V, M>), + Occupied(OccupiedEntry<'a, K, V, M>), +} + +impl<'a, K, V, M: Map + 'a> Entry<'a, K, V, M> { + pub fn and_modify(mut self, f: F) -> Self { + if let Self::Occupied(entry) = &mut self { + f(entry.get_mut()); + } + self + } + /// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key + pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> { + match self { + Self::Vacant(entry) => entry.insert_entry(v), + Self::Occupied(mut entry) => { + entry.insert(v); + entry + } + } + } + pub fn key(&self) -> &K { + match self { + Self::Vacant(entry) => entry.key(), + Self::Occupied(entry) => entry.key(), + } + } + /// inserts a new key as a new set + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + self.or_insert_with(V::default) + } + /// inserts a new key as a new set + pub fn or_insert(self, v: V) -> &'a mut V { + match self { + Self::Vacant(entry) => entry.insert(v), + Self::Occupied(entry) => entry.into_mut(), + } + } + /// inserts a new key as a new set + pub fn or_insert_with V>(self, f: F) -> &'a mut V { + match self { + Self::Vacant(entry) => entry.insert(f()), + Self::Occupied(entry) => entry.into_mut(), + } + } + /// inserts a new key as a new set + pub fn or_insert_with_key V>(self, f: F) -> &'a mut V { + match self { + Self::Vacant(entry) => { + let v = f(entry.key()); + entry.insert(v) + } + Self::Occupied(entry) => entry.into_mut(), + } + } +} diff --git a/crates/fayalite/tests/deduce_structural_eq_flags.rs b/crates/fayalite/tests/deduce_structural_eq_flags.rs new file mode 100644 index 0000000..4633132 --- /dev/null +++ b/crates/fayalite/tests/deduce_structural_eq_flags.rs @@ -0,0 +1,4127 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information +use fayalite::{ + assert_export_firrtl, + expr::{ExprEnum, ops::StructuralEq, target::GetTarget}, + firrtl::ExportOptions, + intern::Intern, + module::{ + StmtConnect, + transform::{ + deduce_structural_eq_flags::deduce_structural_eq_flags_with_debug_tracing, + simplify_enums::{SimplifyEnumsKind, simplify_enums}, + visit::{Visit, Visitor}, + }, + }, + prelude::*, +}; +use std::convert::Infallible; + +#[hdl(outline_generated)] +struct CheckStructuralEqOut { + opt_unit_flip: Bool, + opt_unit: Bool, + opt_bool_flip: Bool, + opt_bool: Bool, + opt_opt_unit_flip: Bool, + opt_opt_unit: Bool, + array_opt_bool_flip: Bool, + array_opt_bool: Bool, + struct_opt_bool_flip: Bool, + struct_opt_bool: Bool, +} + +#[hdl(outline_generated)] +struct CheckStructuralEqModuleIO { + #[hdl(flip)] + opt_unit_flip: HdlOption<()>, + opt_unit: HdlOption<()>, + #[hdl(flip)] + opt_bool_flip: HdlOption, + opt_bool: HdlOption, + #[hdl(flip)] + opt_opt_unit_flip: HdlOption>, + opt_opt_unit: HdlOption>, + #[hdl(flip)] + array_opt_bool_flip: Array, 2>, + array_opt_bool: Array, 2>, + #[hdl(flip)] + struct_opt_bool_flip: (HdlOption, Bool), + struct_opt_bool: (HdlOption, Bool), +} + +#[hdl_module(extern, outline_generated)] +fn check_deduce_structural_eq_flags_extern_child() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.output(); +} + +#[hdl_module(outline_generated)] +fn check_deduce_structural_eq_flags_child() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.output(); + #[hdl] + let CheckStructuralEqModuleIO { + opt_unit_flip, + opt_unit, + opt_bool_flip, + opt_bool, + opt_opt_unit_flip, + opt_opt_unit, + array_opt_bool_flip, + array_opt_bool, + struct_opt_bool_flip, + struct_opt_bool, + } = io; + connect(opt_unit, opt_unit_flip); + connect(opt_bool, opt_bool_flip); + connect(opt_opt_unit, opt_opt_unit_flip); + connect(array_opt_bool, array_opt_bool_flip); + connect(struct_opt_bool, struct_opt_bool_flip); +} + +#[hdl_module(outline_generated)] +fn check_deduce_structural_eq_flags_parent() { + #[hdl] + let io: CheckStructuralEqModuleIO = m.input(); + #[hdl] + let io_zeros: CheckStructuralEqModuleIO = m.input(); + #[hdl] + let io_alternating: CheckStructuralEqModuleIO = m.input(); + + #[hdl] + let parent_out: CheckStructuralEqOut = m.output(); + #[hdl] + let parent_zeros_out: CheckStructuralEqOut = m.output(); + #[hdl] + let parent_alternating_out: CheckStructuralEqOut = m.output(); + #[hdl] + let extern_child_out: CheckStructuralEqOut = m.output(); + #[hdl] + let child_out: CheckStructuralEqOut = m.output(); + + #[hdl] + let extern_child = instance(check_deduce_structural_eq_flags_extern_child()); + #[hdl] + let child = instance(check_deduce_structural_eq_flags_child()); + + trait MapLiteral { + fn map_literal(&self, expr: impl ToExpr) -> Expr; + } + + impl) -> Expr> MapLiteral for F { + fn map_literal(&self, expr: impl ToExpr) -> Expr { + Expr::from_canonical(self(Expr::canonical(expr.to_expr()))) + } + } + + #[hdl] + fn connect_io( + io_in: Expr, + out: Expr, + map_literal: impl MapLiteral, + ) { + #[hdl] + let CheckStructuralEqModuleIO { + opt_unit_flip, + opt_unit, + opt_bool_flip, + opt_bool, + opt_opt_unit_flip, + opt_opt_unit, + array_opt_bool_flip, + array_opt_bool, + struct_opt_bool_flip, + struct_opt_bool, + } = io_in; + macro_rules! connect_pair { + ($field_flip:ident, $field:ident, $literal:expr $(,)?) => { + let literal = map_literal.map_literal($literal); + connect($field_flip, literal); + connect( + out.$field, + StructuralEq::new(Expr::canonical($field), Expr::canonical(literal)), + ); + connect( + out.$field_flip, + StructuralEq::new(Expr::canonical($field_flip), Expr::canonical(literal)), + ); + }; + } + connect_pair!(opt_unit_flip, opt_unit, HdlSome(())); + connect_pair!(opt_bool_flip, opt_bool, HdlSome(true)); + connect_pair!(opt_opt_unit_flip, opt_opt_unit, HdlSome(HdlSome(()))); + connect_pair!( + array_opt_bool_flip, + array_opt_bool, + [HdlSome(false), HdlSome(true)], + ); + connect_pair!(struct_opt_bool_flip, struct_opt_bool, (HdlSome(true), true)); + }; + + connect_io(io, parent_out, |expr| expr); + connect_io(io_zeros, parent_zeros_out, |expr: Expr| { + let ty = expr.ty(); + let bits = UInt[ty.bit_width()].zero().to_expr(); + bits.cast_bits_to(ty) + }); + connect_io( + io_alternating, + parent_alternating_out, + |expr: Expr| { + let ty = expr.ty(); + let bits = u128::from_le_bytes([0xAA; _]) + .cast_to(UInt[ty.bit_width()]) + .to_expr(); + bits.cast_bits_to(ty) + }, + ); + connect_io(extern_child.io, extern_child_out, |expr| expr); + connect_io(child.io, child_out, |expr| expr); +} + +#[test] +fn test_deduce_structural_eq_flags() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = check_deduce_structural_eq_flags_parent(); + dbg!(m); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {} + type Ty1 = {|HdlNone, HdlSome: Ty0|} + type Ty2 = {|HdlNone, HdlSome: UInt<1>|} + type Ty3 = {|HdlNone, HdlSome: Ty1|} + type Ty4 = {`0`: Ty2, `1`: UInt<1>} + type Ty5 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty3, opt_opt_unit: Ty3, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty4, struct_opt_bool: Ty4} + type Ty6 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty7 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty8 = {io: Ty5} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty5 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty5 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty5 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty6 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty6 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty6 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty6 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty6 @[module-XXXXXXXXXX.rs 9:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + invalidate _bundle_literal_expr + connect io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome): + connect _cast_enum_to_bits_expr, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr): + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_1): + connect _cast_enum_to_bits_expr_1, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_2): + connect _cast_enum_to_bits_expr_2, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_3: UInt<2> + match io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_3): + connect _cast_enum_to_bits_expr_3, pad(cat(_cast_enum_to_bits_expr_HdlSome_3, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_4: UInt<2> + match {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)): + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_4): + connect _cast_enum_to_bits_expr_4, pad(cat(_cast_enum_to_bits_expr_HdlSome_4, UInt<1>(1)), 2) + connect parent_out.opt_bool, eq(_cast_enum_to_bits_expr_3, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_5: UInt<2> + match io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_5): + connect _cast_enum_to_bits_expr_5, pad(cat(_cast_enum_to_bits_expr_HdlSome_5, UInt<1>(1)), 2) + connect parent_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_5, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_6: UInt<2> + match io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_6): + wire _cast_enum_to_bits_expr_7: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_6: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_7): + connect _cast_enum_to_bits_expr_7, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_6, pad(cat(_cast_enum_to_bits_expr_7, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_8: UInt<2> + match {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)): + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_8): + wire _cast_enum_to_bits_expr_9: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_8: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_9): + connect _cast_enum_to_bits_expr_9, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_8, pad(cat(_cast_enum_to_bits_expr_9, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_6, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_10: UInt<2> + match io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_10): + wire _cast_enum_to_bits_expr_11: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_10: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_11): + connect _cast_enum_to_bits_expr_11, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_10, pad(cat(_cast_enum_to_bits_expr_11, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_10, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + connect _array_literal_expr[0], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h0)) + connect _array_literal_expr[1], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_12: UInt<2> + match io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_12): + connect _cast_enum_to_bits_expr_12, pad(cat(_cast_enum_to_bits_expr_HdlSome_12, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_13: UInt<2> + match _array_literal_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_13): + connect _cast_enum_to_bits_expr_13, pad(cat(_cast_enum_to_bits_expr_HdlSome_13, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_14: UInt<2> + match io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_14): + connect _cast_enum_to_bits_expr_14, pad(cat(_cast_enum_to_bits_expr_HdlSome_14, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_15: UInt<2> + match _array_literal_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_15): + connect _cast_enum_to_bits_expr_15, pad(cat(_cast_enum_to_bits_expr_HdlSome_15, UInt<1>(1)), 2) + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_enum_to_bits_expr_12, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_14, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool, _array_structural_eq @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_16: UInt<2> + match io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_16): + connect _cast_enum_to_bits_expr_16, pad(cat(_cast_enum_to_bits_expr_HdlSome_16, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_17: UInt<2> + match io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_17): + connect _cast_enum_to_bits_expr_17, pad(cat(_cast_enum_to_bits_expr_HdlSome_17, UInt<1>(1)), 2) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_17, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool_flip, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_1: Ty4 + connect _bundle_literal_expr_1.`0`, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect _bundle_literal_expr_1.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_18: UInt<2> + match io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_18): + connect _cast_enum_to_bits_expr_18, pad(cat(_cast_enum_to_bits_expr_HdlSome_18, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_19: UInt<2> + match _bundle_literal_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_19): + connect _cast_enum_to_bits_expr_19, pad(cat(_cast_enum_to_bits_expr_HdlSome_19, UInt<1>(1)), 2) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr_18, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool, _bundle_structural_eq @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_20: UInt<2> + match io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_20): + connect _cast_enum_to_bits_expr_20, pad(cat(_cast_enum_to_bits_expr_HdlSome_20, UInt<1>(1)), 2) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_20, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_enum_expr: Ty1 + when eq(UInt<1>(0), tail(UInt<1>(0h0), 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + wire _cast_bits_to_bundle_expr: Ty0 + invalidate _cast_bits_to_bundle_expr + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect io_zeros.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_21): + connect _cast_enum_to_bits_expr_21, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_enum_expr: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_22): + connect _cast_enum_to_bits_expr_22, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit, eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_zeros.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_23): + connect _cast_enum_to_bits_expr_23, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_1: Ty2 + wire _cast_bits_to_enum_expr_body_1: UInt<1> + connect _cast_bits_to_enum_expr_body_1, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_1) + connect io_zeros.opt_bool_flip, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_24: UInt<2> + match io_zeros.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_24): + connect _cast_enum_to_bits_expr_24, pad(cat(_cast_enum_to_bits_expr_HdlSome_24, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_25: UInt<2> + match _cast_bits_to_enum_expr_1: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_25): + connect _cast_enum_to_bits_expr_25, pad(cat(_cast_enum_to_bits_expr_HdlSome_25, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool, eq(_cast_enum_to_bits_expr_24, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_26: UInt<2> + match io_zeros.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_26): + connect _cast_enum_to_bits_expr_26, pad(cat(_cast_enum_to_bits_expr_HdlSome_26, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_2: Ty3 + wire _cast_bits_to_enum_expr_body_2: UInt<1> + connect _cast_bits_to_enum_expr_body_2, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_3: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_2, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_3) + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_enum_expr_2 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_27: UInt<2> + match io_zeros.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_27): + wire _cast_enum_to_bits_expr_28: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_27: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_28): + connect _cast_enum_to_bits_expr_28, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_27, pad(cat(_cast_enum_to_bits_expr_28, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_29: UInt<2> + match _cast_bits_to_enum_expr_2: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_29): + wire _cast_enum_to_bits_expr_30: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_29: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_30): + connect _cast_enum_to_bits_expr_30, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_29, pad(cat(_cast_enum_to_bits_expr_30, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_31: UInt<2> + match io_zeros.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_31): + wire _cast_enum_to_bits_expr_32: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_31: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_32): + connect _cast_enum_to_bits_expr_32, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_31, pad(cat(_cast_enum_to_bits_expr_32, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_4: Ty2 + wire _cast_bits_to_enum_expr_body_4: UInt<1> + connect _cast_bits_to_enum_expr_body_4, head(_cast_bits_to_array_expr_flattened[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[0], 1)): + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_4) + connect _cast_bits_to_array_expr[0], _cast_bits_to_enum_expr_4 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_enum_expr_5: Ty2 + wire _cast_bits_to_enum_expr_body_5: UInt<1> + connect _cast_bits_to_enum_expr_body_5, head(_cast_bits_to_array_expr_flattened[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[1], 1)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_5) + connect _cast_bits_to_array_expr[1], _cast_bits_to_enum_expr_5 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_33: UInt<2> + match io_zeros.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_33): + connect _cast_enum_to_bits_expr_33, pad(cat(_cast_enum_to_bits_expr_HdlSome_33, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_34: UInt<2> + match _cast_bits_to_array_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_34): + connect _cast_enum_to_bits_expr_34, pad(cat(_cast_enum_to_bits_expr_HdlSome_34, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_35: UInt<2> + match io_zeros.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_35): + connect _cast_enum_to_bits_expr_35, pad(cat(_cast_enum_to_bits_expr_HdlSome_35, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_36: UInt<2> + match _cast_bits_to_array_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_36): + connect _cast_enum_to_bits_expr_36, pad(cat(_cast_enum_to_bits_expr_HdlSome_36, UInt<1>(1)), 2) + wire _array_structural_eq_2: UInt<1> + connect _array_structural_eq_2, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool, _array_structural_eq_2 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_37: UInt<2> + match io_zeros.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_37): + connect _cast_enum_to_bits_expr_37, pad(cat(_cast_enum_to_bits_expr_HdlSome_37, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_38: UInt<2> + match io_zeros.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_38): + connect _cast_enum_to_bits_expr_38, pad(cat(_cast_enum_to_bits_expr_HdlSome_38, UInt<1>(1)), 2) + wire _array_structural_eq_3: UInt<1> + connect _array_structural_eq_3, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool_flip, _array_structural_eq_3 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_6: Ty2 + wire _cast_bits_to_enum_expr_body_6: UInt<1> + connect _cast_bits_to_enum_expr_body_6, head(_cast_bits_to_bundle_expr_flattened.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.`0`, 1)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_6) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_39: UInt<2> + match io_zeros.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_39): + connect _cast_enum_to_bits_expr_39, pad(cat(_cast_enum_to_bits_expr_HdlSome_39, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_40: UInt<2> + match _cast_bits_to_bundle_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_40): + connect _cast_enum_to_bits_expr_40, pad(cat(_cast_enum_to_bits_expr_HdlSome_40, UInt<1>(1)), 2) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_41: UInt<2> + match io_zeros.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_41): + connect _cast_enum_to_bits_expr_41, pad(cat(_cast_enum_to_bits_expr_HdlSome_41, UInt<1>(1)), 2) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match io_alternating.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_42): + connect _cast_enum_to_bits_expr_42, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit, eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_43: UInt<1> + match io_alternating.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_43): + connect _cast_enum_to_bits_expr_43, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_7: Ty2 + wire _cast_bits_to_enum_expr_body_7: UInt<1> + connect _cast_bits_to_enum_expr_body_7, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_7) + connect io_alternating.opt_bool_flip, _cast_bits_to_enum_expr_7 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_44: UInt<2> + match io_alternating.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_44): + connect _cast_enum_to_bits_expr_44, pad(cat(_cast_enum_to_bits_expr_HdlSome_44, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_45: UInt<2> + match _cast_bits_to_enum_expr_7: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_45): + connect _cast_enum_to_bits_expr_45, pad(cat(_cast_enum_to_bits_expr_HdlSome_45, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool, eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_46: UInt<2> + match io_alternating.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_46): + connect _cast_enum_to_bits_expr_46, pad(cat(_cast_enum_to_bits_expr_HdlSome_46, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_46, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_8: Ty3 + wire _cast_bits_to_enum_expr_body_8: UInt<1> + connect _cast_bits_to_enum_expr_body_8, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_9: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_8, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_9) + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_enum_expr_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_47: UInt<2> + match io_alternating.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_47): + wire _cast_enum_to_bits_expr_48: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_47: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_48): + connect _cast_enum_to_bits_expr_48, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_47, pad(cat(_cast_enum_to_bits_expr_48, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_49: UInt<2> + match _cast_bits_to_enum_expr_8: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_49): + wire _cast_enum_to_bits_expr_50: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_49: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_50): + connect _cast_enum_to_bits_expr_50, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_49, pad(cat(_cast_enum_to_bits_expr_50, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_51: UInt<2> + match io_alternating.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_51): + wire _cast_enum_to_bits_expr_52: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_51: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_52): + connect _cast_enum_to_bits_expr_52, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_51, pad(cat(_cast_enum_to_bits_expr_52, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_enum_expr_10: Ty2 + wire _cast_bits_to_enum_expr_body_10: UInt<1> + connect _cast_bits_to_enum_expr_body_10, head(_cast_bits_to_array_expr_flattened_1[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[0], 1)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_10) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_enum_expr_10 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_enum_expr_11: Ty2 + wire _cast_bits_to_enum_expr_body_11: UInt<1> + connect _cast_bits_to_enum_expr_body_11, head(_cast_bits_to_array_expr_flattened_1[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[1], 1)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_11) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_enum_expr_11 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_53: UInt<2> + match io_alternating.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_53): + connect _cast_enum_to_bits_expr_53, pad(cat(_cast_enum_to_bits_expr_HdlSome_53, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_54: UInt<2> + match _cast_bits_to_array_expr_1[0]: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_54): + connect _cast_enum_to_bits_expr_54, pad(cat(_cast_enum_to_bits_expr_HdlSome_54, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_55: UInt<2> + match io_alternating.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_55): + connect _cast_enum_to_bits_expr_55, pad(cat(_cast_enum_to_bits_expr_HdlSome_55, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_56: UInt<2> + match _cast_bits_to_array_expr_1[1]: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_56): + connect _cast_enum_to_bits_expr_56, pad(cat(_cast_enum_to_bits_expr_HdlSome_56, UInt<1>(1)), 2) + wire _array_structural_eq_4: UInt<1> + connect _array_structural_eq_4, and(eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool, _array_structural_eq_4 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_57: UInt<2> + match io_alternating.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_57): + connect _cast_enum_to_bits_expr_57, pad(cat(_cast_enum_to_bits_expr_HdlSome_57, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_58: UInt<2> + match io_alternating.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_58): + connect _cast_enum_to_bits_expr_58, pad(cat(_cast_enum_to_bits_expr_HdlSome_58, UInt<1>(1)), 2) + wire _array_structural_eq_5: UInt<1> + connect _array_structural_eq_5, and(eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool_flip, _array_structural_eq_5 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty7 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_enum_expr_12: Ty2 + wire _cast_bits_to_enum_expr_body_12: UInt<1> + connect _cast_bits_to_enum_expr_body_12, head(_cast_bits_to_bundle_expr_flattened_1.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.`0`, 1)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_12) + connect _cast_bits_to_bundle_expr_2.`0`, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_2.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_59: UInt<2> + match io_alternating.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_59): + connect _cast_enum_to_bits_expr_59, pad(cat(_cast_enum_to_bits_expr_HdlSome_59, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_60: UInt<2> + match _cast_bits_to_bundle_expr_2.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_60): + connect _cast_enum_to_bits_expr_60, pad(cat(_cast_enum_to_bits_expr_HdlSome_60, UInt<1>(1)), 2) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool, _bundle_structural_eq_4 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_61: UInt<2> + match io_alternating.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_61): + connect _cast_enum_to_bits_expr_61, pad(cat(_cast_enum_to_bits_expr_HdlSome_61, UInt<1>(1)), 2) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_61, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool_flip, _bundle_structural_eq_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match extern_child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_62): + connect _cast_enum_to_bits_expr_62, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit, eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_63: UInt<1> + match extern_child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_63): + connect _cast_enum_to_bits_expr_63, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_64: UInt<2> + match extern_child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_64): + connect _cast_enum_to_bits_expr_64, pad(cat(_cast_enum_to_bits_expr_HdlSome_64, UInt<1>(1)), 2) + connect extern_child_out.opt_bool, eq(_cast_enum_to_bits_expr_64, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_65: UInt<2> + match extern_child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_65): + connect _cast_enum_to_bits_expr_65, pad(cat(_cast_enum_to_bits_expr_HdlSome_65, UInt<1>(1)), 2) + connect extern_child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_65, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_66: UInt<2> + match extern_child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_66): + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_66: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_67): + connect _cast_enum_to_bits_expr_67, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_66, pad(cat(_cast_enum_to_bits_expr_67, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_68: UInt<2> + match extern_child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_68): + wire _cast_enum_to_bits_expr_69: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_68: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_69): + connect _cast_enum_to_bits_expr_69, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_68, pad(cat(_cast_enum_to_bits_expr_69, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_68, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_70: UInt<2> + match extern_child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_70): + connect _cast_enum_to_bits_expr_70, pad(cat(_cast_enum_to_bits_expr_HdlSome_70, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_71: UInt<2> + match extern_child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_71): + connect _cast_enum_to_bits_expr_71, pad(cat(_cast_enum_to_bits_expr_HdlSome_71, UInt<1>(1)), 2) + wire _array_structural_eq_6: UInt<1> + connect _array_structural_eq_6, and(eq(_cast_enum_to_bits_expr_70, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_71, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool, _array_structural_eq_6 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_72: UInt<2> + match extern_child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_72): + connect _cast_enum_to_bits_expr_72, pad(cat(_cast_enum_to_bits_expr_HdlSome_72, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_73: UInt<2> + match extern_child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_73): + connect _cast_enum_to_bits_expr_73, pad(cat(_cast_enum_to_bits_expr_HdlSome_73, UInt<1>(1)), 2) + wire _array_structural_eq_7: UInt<1> + connect _array_structural_eq_7, and(eq(_cast_enum_to_bits_expr_72, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool_flip, _array_structural_eq_7 @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_74: UInt<2> + match extern_child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_74): + connect _cast_enum_to_bits_expr_74, pad(cat(_cast_enum_to_bits_expr_HdlSome_74, UInt<1>(1)), 2) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_75: UInt<2> + match extern_child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_75): + connect _cast_enum_to_bits_expr_75, pad(cat(_cast_enum_to_bits_expr_HdlSome_75, UInt<1>(1)), 2) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_75, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_76: UInt<1> + match child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_76): + connect _cast_enum_to_bits_expr_76, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit, eq(_cast_enum_to_bits_expr_76, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_77): + connect _cast_enum_to_bits_expr_77, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_78: UInt<2> + match child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_78): + connect _cast_enum_to_bits_expr_78, pad(cat(_cast_enum_to_bits_expr_HdlSome_78, UInt<1>(1)), 2) + connect child_out.opt_bool, eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_79: UInt<2> + match child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_79): + connect _cast_enum_to_bits_expr_79, pad(cat(_cast_enum_to_bits_expr_HdlSome_79, UInt<1>(1)), 2) + connect child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_80: UInt<2> + match child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_80): + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_80: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_81): + connect _cast_enum_to_bits_expr_81, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_80, pad(cat(_cast_enum_to_bits_expr_81, UInt<1>(1)), 2) + connect child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_82: UInt<2> + match child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_82): + wire _cast_enum_to_bits_expr_83: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_82: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_83): + connect _cast_enum_to_bits_expr_83, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_82, pad(cat(_cast_enum_to_bits_expr_83, UInt<1>(1)), 2) + connect child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_84: UInt<2> + match child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_84): + connect _cast_enum_to_bits_expr_84, pad(cat(_cast_enum_to_bits_expr_HdlSome_84, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_85: UInt<2> + match child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_85, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_85): + connect _cast_enum_to_bits_expr_85, pad(cat(_cast_enum_to_bits_expr_HdlSome_85, UInt<1>(1)), 2) + wire _array_structural_eq_8: UInt<1> + connect _array_structural_eq_8, and(eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_85, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool, _array_structural_eq_8 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_86: UInt<2> + match child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_86, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_86): + connect _cast_enum_to_bits_expr_86, pad(cat(_cast_enum_to_bits_expr_HdlSome_86, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_87: UInt<2> + match child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_87, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_87): + connect _cast_enum_to_bits_expr_87, pad(cat(_cast_enum_to_bits_expr_HdlSome_87, UInt<1>(1)), 2) + wire _array_structural_eq_9: UInt<1> + connect _array_structural_eq_9, and(eq(_cast_enum_to_bits_expr_86, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_87, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool_flip, _array_structural_eq_9 @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_88: UInt<2> + match child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_88, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_88): + connect _cast_enum_to_bits_expr_88, pad(cat(_cast_enum_to_bits_expr_HdlSome_88, UInt<1>(1)), 2) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_88, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_89: UInt<2> + match child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_89, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_89): + connect _cast_enum_to_bits_expr_89, pad(cat(_cast_enum_to_bits_expr_HdlSome_89, UInt<1>(1)), 2) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_89, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 17:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m = deduce_structural_eq_flags_with_debug_tracing(m.canonical().intern_sized(), true); + dbg!(m); + struct MyVisitor(Vec<(String, bool)>); + macro_rules! connects { + {$($key:literal: $value:literal),* $(,)?} => { + const KNOWN_CONNECTS: &[(&str, bool)] = &[$(($key, $value)),*]; + }; + } + + connects! { + "check_deduce_structural_eq_flags_parent::parent_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::parent_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_zeros_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.opt_opt_unit_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.array_opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::parent_alternating_out.struct_opt_bool_flip": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_opt_unit": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.array_opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::extern_child_out.struct_opt_bool": false, + "check_deduce_structural_eq_flags_parent::extern_child_out.struct_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_unit": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_opt_unit": true, + "check_deduce_structural_eq_flags_parent::child_out.opt_opt_unit_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.array_opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.array_opt_bool_flip": true, + "check_deduce_structural_eq_flags_parent::child_out.struct_opt_bool": true, + "check_deduce_structural_eq_flags_parent::child_out.struct_opt_bool_flip": true, + } + + impl Visitor for MyVisitor { + type Error = Infallible; + fn visit_stmt_connect(&mut self, v: &StmtConnect) -> Result<(), Self::Error> { + let ExprEnum::StructuralEq(structural_eq) = *Expr::expr_enum(v.rhs) else { + return v.default_visit(self); + }; + let Some(lhs_target) = v.lhs.target() else { + panic!("connect lhs must have a Target: {v:#?}"); + }; + let lhs_target_str = lhs_target.to_string(); + let assume_padding_is_zeroed = structural_eq.flags().assume_padding_is_zeroed; + if let Some(key) = KNOWN_CONNECTS + .iter() + .copied() + .find(|&(key, _)| key == lhs_target_str) + { + if assume_padding_is_zeroed != key.1 { + println!("{key:?}: {v:#?}"); + panic!( + "{key:?}: assume_padding_is_zeroed ({assume_padding_is_zeroed}) is not as expected" + ); + } + } else { + let k = (lhs_target_str, assume_padding_is_zeroed); + println!("{k:?}: {v:#?}"); + self.0.push(k); + } + Ok(()) + } + } + let mut visitor = MyVisitor(vec![]); + let Ok(()) = visitor.visit_module(&m); + if !visitor.0.is_empty() { + panic!( + "unknown connects:\nconnects! {:#?}", + std::fmt::from_fn(|f| { f.debug_map().entries(visitor.0.iter().cloned()).finish() }) + ) + } + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {} + type Ty1 = {|HdlNone, HdlSome: Ty0|} + type Ty2 = {|HdlNone, HdlSome: UInt<1>|} + type Ty3 = {|HdlNone, HdlSome: Ty1|} + type Ty4 = {`0`: Ty2, `1`: UInt<1>} + type Ty5 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty3, opt_opt_unit: Ty3, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty4, struct_opt_bool: Ty4} + type Ty6 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty7 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty8 = {io: Ty5} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty5 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty5 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty5 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty6 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty6 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty6 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty6 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty6 @[module-XXXXXXXXXX.rs 9:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + invalidate _bundle_literal_expr + connect io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome): + connect _cast_enum_to_bits_expr, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr): + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_1): + connect _cast_enum_to_bits_expr_1, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_2): + connect _cast_enum_to_bits_expr_2, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_3: UInt<2> + match io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_3): + connect _cast_enum_to_bits_expr_3, pad(cat(_cast_enum_to_bits_expr_HdlSome_3, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_4: UInt<2> + match {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)): + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_4): + connect _cast_enum_to_bits_expr_4, pad(cat(_cast_enum_to_bits_expr_HdlSome_4, UInt<1>(1)), 2) + connect parent_out.opt_bool, eq(_cast_enum_to_bits_expr_3, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_5: UInt<2> + match io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_5): + connect _cast_enum_to_bits_expr_5, pad(cat(_cast_enum_to_bits_expr_HdlSome_5, UInt<1>(1)), 2) + connect parent_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_5, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_6: UInt<2> + match io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_6): + wire _cast_enum_to_bits_expr_7: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_6: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_7): + connect _cast_enum_to_bits_expr_7, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_6, pad(cat(_cast_enum_to_bits_expr_7, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_8: UInt<2> + match {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)): + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_8): + wire _cast_enum_to_bits_expr_9: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_8: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_9): + connect _cast_enum_to_bits_expr_9, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_8, pad(cat(_cast_enum_to_bits_expr_9, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_6, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_10: UInt<2> + match io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_10): + wire _cast_enum_to_bits_expr_11: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_10: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_11): + connect _cast_enum_to_bits_expr_11, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_10, pad(cat(_cast_enum_to_bits_expr_11, UInt<1>(1)), 2) + connect parent_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_10, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + connect _array_literal_expr[0], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h0)) + connect _array_literal_expr[1], {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_12: UInt<2> + match io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_12): + connect _cast_enum_to_bits_expr_12, pad(cat(_cast_enum_to_bits_expr_HdlSome_12, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_13: UInt<2> + match _array_literal_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_13): + connect _cast_enum_to_bits_expr_13, pad(cat(_cast_enum_to_bits_expr_HdlSome_13, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_14: UInt<2> + match io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_14): + connect _cast_enum_to_bits_expr_14, pad(cat(_cast_enum_to_bits_expr_HdlSome_14, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_15: UInt<2> + match _array_literal_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_15): + connect _cast_enum_to_bits_expr_15, pad(cat(_cast_enum_to_bits_expr_HdlSome_15, UInt<1>(1)), 2) + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_enum_to_bits_expr_12, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_14, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool, _array_structural_eq @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_16: UInt<2> + match io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_16): + connect _cast_enum_to_bits_expr_16, pad(cat(_cast_enum_to_bits_expr_HdlSome_16, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_17: UInt<2> + match io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_17): + connect _cast_enum_to_bits_expr_17, pad(cat(_cast_enum_to_bits_expr_HdlSome_17, UInt<1>(1)), 2) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_17, _cast_enum_to_bits_expr_15)) + connect parent_out.array_opt_bool_flip, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_1: Ty4 + connect _bundle_literal_expr_1.`0`, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) + connect _bundle_literal_expr_1.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_18: UInt<2> + match io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_18): + connect _cast_enum_to_bits_expr_18, pad(cat(_cast_enum_to_bits_expr_HdlSome_18, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_19: UInt<2> + match _bundle_literal_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_19): + connect _cast_enum_to_bits_expr_19, pad(cat(_cast_enum_to_bits_expr_HdlSome_19, UInt<1>(1)), 2) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr_18, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool, _bundle_structural_eq @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_20: UInt<2> + match io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_20): + connect _cast_enum_to_bits_expr_20, pad(cat(_cast_enum_to_bits_expr_HdlSome_20, UInt<1>(1)), 2) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_20, _cast_enum_to_bits_expr_19), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect parent_out.struct_opt_bool_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_enum_expr: Ty1 + when eq(UInt<1>(0), tail(UInt<1>(0h0), 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + wire _cast_bits_to_bundle_expr: Ty0 + invalidate _cast_bits_to_bundle_expr + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect io_zeros.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_21): + connect _cast_enum_to_bits_expr_21, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_enum_expr: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_22): + connect _cast_enum_to_bits_expr_22, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit, eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_zeros.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_23): + connect _cast_enum_to_bits_expr_23, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_zeros_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_1: Ty2 + wire _cast_bits_to_enum_expr_body_1: UInt<1> + connect _cast_bits_to_enum_expr_body_1, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_1) + connect io_zeros.opt_bool_flip, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_24: UInt<2> + match io_zeros.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_24): + connect _cast_enum_to_bits_expr_24, pad(cat(_cast_enum_to_bits_expr_HdlSome_24, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_25: UInt<2> + match _cast_bits_to_enum_expr_1: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_25): + connect _cast_enum_to_bits_expr_25, pad(cat(_cast_enum_to_bits_expr_HdlSome_25, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool, eq(_cast_enum_to_bits_expr_24, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_26: UInt<2> + match io_zeros.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_26): + connect _cast_enum_to_bits_expr_26, pad(cat(_cast_enum_to_bits_expr_HdlSome_26, UInt<1>(1)), 2) + connect parent_zeros_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_25) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_2: Ty3 + wire _cast_bits_to_enum_expr_body_2: UInt<1> + connect _cast_bits_to_enum_expr_body_2, head(UInt<2>(0h0), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h0), 1)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_3: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_2, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_3) + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_enum_expr_2 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_27: UInt<2> + match io_zeros.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_27): + wire _cast_enum_to_bits_expr_28: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_27: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_28): + connect _cast_enum_to_bits_expr_28, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_27, pad(cat(_cast_enum_to_bits_expr_28, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_29: UInt<2> + match _cast_bits_to_enum_expr_2: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_29): + wire _cast_enum_to_bits_expr_30: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_29: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_30): + connect _cast_enum_to_bits_expr_30, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_29, pad(cat(_cast_enum_to_bits_expr_30, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_31: UInt<2> + match io_zeros.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_31): + wire _cast_enum_to_bits_expr_32: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_31: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_32): + connect _cast_enum_to_bits_expr_32, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_31, pad(cat(_cast_enum_to_bits_expr_32, UInt<1>(1)), 2) + connect parent_zeros_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_29) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_4: Ty2 + wire _cast_bits_to_enum_expr_body_4: UInt<1> + connect _cast_bits_to_enum_expr_body_4, head(_cast_bits_to_array_expr_flattened[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[0], 1)): + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_4) + connect _cast_bits_to_array_expr[0], _cast_bits_to_enum_expr_4 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_enum_expr_5: Ty2 + wire _cast_bits_to_enum_expr_body_5: UInt<1> + connect _cast_bits_to_enum_expr_body_5, head(_cast_bits_to_array_expr_flattened[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened[1], 1)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_5) + connect _cast_bits_to_array_expr[1], _cast_bits_to_enum_expr_5 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_33: UInt<2> + match io_zeros.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_33): + connect _cast_enum_to_bits_expr_33, pad(cat(_cast_enum_to_bits_expr_HdlSome_33, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_34: UInt<2> + match _cast_bits_to_array_expr[0]: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_34): + connect _cast_enum_to_bits_expr_34, pad(cat(_cast_enum_to_bits_expr_HdlSome_34, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_35: UInt<2> + match io_zeros.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_35): + connect _cast_enum_to_bits_expr_35, pad(cat(_cast_enum_to_bits_expr_HdlSome_35, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_36: UInt<2> + match _cast_bits_to_array_expr[1]: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_36): + connect _cast_enum_to_bits_expr_36, pad(cat(_cast_enum_to_bits_expr_HdlSome_36, UInt<1>(1)), 2) + wire _array_structural_eq_2: UInt<1> + connect _array_structural_eq_2, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool, _array_structural_eq_2 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_37: UInt<2> + match io_zeros.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_37): + connect _cast_enum_to_bits_expr_37, pad(cat(_cast_enum_to_bits_expr_HdlSome_37, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_38: UInt<2> + match io_zeros.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_38): + connect _cast_enum_to_bits_expr_38, pad(cat(_cast_enum_to_bits_expr_HdlSome_38, UInt<1>(1)), 2) + wire _array_structural_eq_3: UInt<1> + connect _array_structural_eq_3, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_34), eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_36)) + connect parent_zeros_out.array_opt_bool_flip, _array_structural_eq_3 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_enum_expr_6: Ty2 + wire _cast_bits_to_enum_expr_body_6: UInt<1> + connect _cast_bits_to_enum_expr_body_6, head(_cast_bits_to_bundle_expr_flattened.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.`0`, 1)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_6) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_39: UInt<2> + match io_zeros.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_39): + connect _cast_enum_to_bits_expr_39, pad(cat(_cast_enum_to_bits_expr_HdlSome_39, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_40: UInt<2> + match _cast_bits_to_bundle_expr_1.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_40): + connect _cast_enum_to_bits_expr_40, pad(cat(_cast_enum_to_bits_expr_HdlSome_40, UInt<1>(1)), 2) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_41: UInt<2> + match io_zeros.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_41): + connect _cast_enum_to_bits_expr_41, pad(cat(_cast_enum_to_bits_expr_HdlSome_41, UInt<1>(1)), 2) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_40), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) + connect parent_zeros_out.struct_opt_bool_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match io_alternating.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_42): + connect _cast_enum_to_bits_expr_42, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit, eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_43: UInt<1> + match io_alternating.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_43): + connect _cast_enum_to_bits_expr_43, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect parent_alternating_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_22) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_enum_expr_7: Ty2 + wire _cast_bits_to_enum_expr_body_7: UInt<1> + connect _cast_bits_to_enum_expr_body_7, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_7) + connect io_alternating.opt_bool_flip, _cast_bits_to_enum_expr_7 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_44: UInt<2> + match io_alternating.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_44): + connect _cast_enum_to_bits_expr_44, pad(cat(_cast_enum_to_bits_expr_HdlSome_44, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_45: UInt<2> + match _cast_bits_to_enum_expr_7: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_45): + connect _cast_enum_to_bits_expr_45, pad(cat(_cast_enum_to_bits_expr_HdlSome_45, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool, eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_46: UInt<2> + match io_alternating.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_46): + connect _cast_enum_to_bits_expr_46, pad(cat(_cast_enum_to_bits_expr_HdlSome_46, UInt<1>(1)), 2) + connect parent_alternating_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_46, _cast_enum_to_bits_expr_45) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_bits_to_enum_expr_8: Ty3 + wire _cast_bits_to_enum_expr_body_8: UInt<1> + connect _cast_bits_to_enum_expr_body_8, head(UInt<2>(0h2), 1) + when eq(UInt<1>(0), tail(UInt<2>(0h2), 1)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlNone) + else: + wire _cast_bits_to_enum_expr_9: Ty1 + when eq(UInt<1>(0), tail(_cast_bits_to_enum_expr_body_8, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome: Ty0|}(HdlSome, _cast_bits_to_bundle_expr) + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome: Ty1|}(HdlSome, _cast_bits_to_enum_expr_9) + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_enum_expr_8 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_47: UInt<2> + match io_alternating.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_47): + wire _cast_enum_to_bits_expr_48: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_47: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_48): + connect _cast_enum_to_bits_expr_48, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_47, pad(cat(_cast_enum_to_bits_expr_48, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_49: UInt<2> + match _cast_bits_to_enum_expr_8: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_49): + wire _cast_enum_to_bits_expr_50: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_49: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_50): + connect _cast_enum_to_bits_expr_50, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_49, pad(cat(_cast_enum_to_bits_expr_50, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_51: UInt<2> + match io_alternating.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_51): + wire _cast_enum_to_bits_expr_52: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_51: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_52): + connect _cast_enum_to_bits_expr_52, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_51, pad(cat(_cast_enum_to_bits_expr_52, UInt<1>(1)), 2) + connect parent_alternating_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_49) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_enum_expr_10: Ty2 + wire _cast_bits_to_enum_expr_body_10: UInt<1> + connect _cast_bits_to_enum_expr_body_10, head(_cast_bits_to_array_expr_flattened_1[0], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[0], 1)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_10) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_enum_expr_10 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_enum_expr_11: Ty2 + wire _cast_bits_to_enum_expr_body_11: UInt<1> + connect _cast_bits_to_enum_expr_body_11, head(_cast_bits_to_array_expr_flattened_1[1], 1) + when eq(UInt<1>(0), tail(_cast_bits_to_array_expr_flattened_1[1], 1)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_11) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_enum_expr_11 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_53: UInt<2> + match io_alternating.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_53): + connect _cast_enum_to_bits_expr_53, pad(cat(_cast_enum_to_bits_expr_HdlSome_53, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_54: UInt<2> + match _cast_bits_to_array_expr_1[0]: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_54): + connect _cast_enum_to_bits_expr_54, pad(cat(_cast_enum_to_bits_expr_HdlSome_54, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_55: UInt<2> + match io_alternating.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_55): + connect _cast_enum_to_bits_expr_55, pad(cat(_cast_enum_to_bits_expr_HdlSome_55, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_56: UInt<2> + match _cast_bits_to_array_expr_1[1]: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_56): + connect _cast_enum_to_bits_expr_56, pad(cat(_cast_enum_to_bits_expr_HdlSome_56, UInt<1>(1)), 2) + wire _array_structural_eq_4: UInt<1> + connect _array_structural_eq_4, and(eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool, _array_structural_eq_4 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_57: UInt<2> + match io_alternating.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_57): + connect _cast_enum_to_bits_expr_57, pad(cat(_cast_enum_to_bits_expr_HdlSome_57, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_58: UInt<2> + match io_alternating.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_58): + connect _cast_enum_to_bits_expr_58, pad(cat(_cast_enum_to_bits_expr_HdlSome_58, UInt<1>(1)), 2) + wire _array_structural_eq_5: UInt<1> + connect _array_structural_eq_5, and(eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_54), eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_56)) + connect parent_alternating_out.array_opt_bool_flip, _array_structural_eq_5 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty7 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_enum_expr_12: Ty2 + wire _cast_bits_to_enum_expr_body_12: UInt<1> + connect _cast_bits_to_enum_expr_body_12, head(_cast_bits_to_bundle_expr_flattened_1.`0`, 1) + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.`0`, 1)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, _cast_bits_to_enum_expr_body_12) + connect _cast_bits_to_bundle_expr_2.`0`, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_2.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_59: UInt<2> + match io_alternating.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_59): + connect _cast_enum_to_bits_expr_59, pad(cat(_cast_enum_to_bits_expr_HdlSome_59, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_60: UInt<2> + match _cast_bits_to_bundle_expr_2.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_60): + connect _cast_enum_to_bits_expr_60, pad(cat(_cast_enum_to_bits_expr_HdlSome_60, UInt<1>(1)), 2) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool, _bundle_structural_eq_4 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_61: UInt<2> + match io_alternating.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_61): + connect _cast_enum_to_bits_expr_61, pad(cat(_cast_enum_to_bits_expr_HdlSome_61, UInt<1>(1)), 2) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_61, _cast_enum_to_bits_expr_60), eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_2.`1`)) + connect parent_alternating_out.struct_opt_bool_flip, _bundle_structural_eq_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match extern_child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_62): + connect _cast_enum_to_bits_expr_62, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit, eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_63: UInt<1> + match extern_child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_63): + connect _cast_enum_to_bits_expr_63, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect extern_child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_64: UInt<2> + match extern_child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_64): + connect _cast_enum_to_bits_expr_64, pad(cat(_cast_enum_to_bits_expr_HdlSome_64, UInt<1>(1)), 2) + connect extern_child_out.opt_bool, eq(_cast_enum_to_bits_expr_64, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_65: UInt<2> + match extern_child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_65): + connect _cast_enum_to_bits_expr_65, pad(cat(_cast_enum_to_bits_expr_HdlSome_65, UInt<1>(1)), 2) + connect extern_child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_65, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_66: UInt<2> + match extern_child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_66): + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_66: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_67): + connect _cast_enum_to_bits_expr_67, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_66, pad(cat(_cast_enum_to_bits_expr_67, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_68: UInt<2> + match extern_child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_68): + wire _cast_enum_to_bits_expr_69: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_68: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_69): + connect _cast_enum_to_bits_expr_69, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_68, pad(cat(_cast_enum_to_bits_expr_69, UInt<1>(1)), 2) + connect extern_child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_68, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_70: UInt<2> + match extern_child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_70): + connect _cast_enum_to_bits_expr_70, pad(cat(_cast_enum_to_bits_expr_HdlSome_70, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_71: UInt<2> + match extern_child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_71): + connect _cast_enum_to_bits_expr_71, pad(cat(_cast_enum_to_bits_expr_HdlSome_71, UInt<1>(1)), 2) + wire _array_structural_eq_6: UInt<1> + connect _array_structural_eq_6, and(eq(_cast_enum_to_bits_expr_70, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_71, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool, _array_structural_eq_6 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_72: UInt<2> + match extern_child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_72): + connect _cast_enum_to_bits_expr_72, pad(cat(_cast_enum_to_bits_expr_HdlSome_72, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_73: UInt<2> + match extern_child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_73): + connect _cast_enum_to_bits_expr_73, pad(cat(_cast_enum_to_bits_expr_HdlSome_73, UInt<1>(1)), 2) + wire _array_structural_eq_7: UInt<1> + connect _array_structural_eq_7, and(eq(_cast_enum_to_bits_expr_72, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_15)) + connect extern_child_out.array_opt_bool_flip, _array_structural_eq_7 @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_74: UInt<2> + match extern_child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_74): + connect _cast_enum_to_bits_expr_74, pad(cat(_cast_enum_to_bits_expr_HdlSome_74, UInt<1>(1)), 2) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool, _bundle_structural_eq_6 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_75: UInt<2> + match extern_child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_75): + connect _cast_enum_to_bits_expr_75, pad(cat(_cast_enum_to_bits_expr_HdlSome_75, UInt<1>(1)), 2) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_75, _cast_enum_to_bits_expr_19), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect extern_child_out.struct_opt_bool_flip, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_76: UInt<1> + match child.io.opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_76): + connect _cast_enum_to_bits_expr_76, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit, eq(_cast_enum_to_bits_expr_76, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match child.io.opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_77): + connect _cast_enum_to_bits_expr_77, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect child_out.opt_unit_flip, eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, {|HdlNone, HdlSome: UInt<1>|}(HdlSome, UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_78: UInt<2> + match child.io.opt_bool: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_78): + connect _cast_enum_to_bits_expr_78, pad(cat(_cast_enum_to_bits_expr_HdlSome_78, UInt<1>(1)), 2) + connect child_out.opt_bool, eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_79: UInt<2> + match child.io.opt_bool_flip: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_79): + connect _cast_enum_to_bits_expr_79, pad(cat(_cast_enum_to_bits_expr_HdlSome_79, UInt<1>(1)), 2) + connect child_out.opt_bool_flip, eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_4) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, {|HdlNone, HdlSome: Ty1|}(HdlSome, {|HdlNone, HdlSome: Ty0|}(HdlSome, _bundle_literal_expr)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_80: UInt<2> + match child.io.opt_opt_unit: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_80): + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_80: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_81): + connect _cast_enum_to_bits_expr_81, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_80, pad(cat(_cast_enum_to_bits_expr_81, UInt<1>(1)), 2) + connect child_out.opt_opt_unit, eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_82: UInt<2> + match child.io.opt_opt_unit_flip: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_82): + wire _cast_enum_to_bits_expr_83: UInt<1> + match _cast_enum_to_bits_expr_HdlSome_82: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_83): + connect _cast_enum_to_bits_expr_83, pad(cat(UInt<0>(0), UInt<1>(1)), 1) + connect _cast_enum_to_bits_expr_82, pad(cat(_cast_enum_to_bits_expr_83, UInt<1>(1)), 2) + connect child_out.opt_opt_unit_flip, eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_8) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_84: UInt<2> + match child.io.array_opt_bool[0]: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_84): + connect _cast_enum_to_bits_expr_84, pad(cat(_cast_enum_to_bits_expr_HdlSome_84, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_85: UInt<2> + match child.io.array_opt_bool[1]: + HdlNone: + connect _cast_enum_to_bits_expr_85, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_85): + connect _cast_enum_to_bits_expr_85, pad(cat(_cast_enum_to_bits_expr_HdlSome_85, UInt<1>(1)), 2) + wire _array_structural_eq_8: UInt<1> + connect _array_structural_eq_8, and(eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_85, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool, _array_structural_eq_8 @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_86: UInt<2> + match child.io.array_opt_bool_flip[0]: + HdlNone: + connect _cast_enum_to_bits_expr_86, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_86): + connect _cast_enum_to_bits_expr_86, pad(cat(_cast_enum_to_bits_expr_HdlSome_86, UInt<1>(1)), 2) + wire _cast_enum_to_bits_expr_87: UInt<2> + match child.io.array_opt_bool_flip[1]: + HdlNone: + connect _cast_enum_to_bits_expr_87, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_87): + connect _cast_enum_to_bits_expr_87, pad(cat(_cast_enum_to_bits_expr_HdlSome_87, UInt<1>(1)), 2) + wire _array_structural_eq_9: UInt<1> + connect _array_structural_eq_9, and(eq(_cast_enum_to_bits_expr_86, _cast_enum_to_bits_expr_13), eq(_cast_enum_to_bits_expr_87, _cast_enum_to_bits_expr_15)) + connect child_out.array_opt_bool_flip, _array_structural_eq_9 @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_88: UInt<2> + match child.io.struct_opt_bool.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_88, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_88): + connect _cast_enum_to_bits_expr_88, pad(cat(_cast_enum_to_bits_expr_HdlSome_88, UInt<1>(1)), 2) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_88, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_89: UInt<2> + match child.io.struct_opt_bool_flip.`0`: + HdlNone: + connect _cast_enum_to_bits_expr_89, UInt<2>(0) + HdlSome(_cast_enum_to_bits_expr_HdlSome_89): + connect _cast_enum_to_bits_expr_89, pad(cat(_cast_enum_to_bits_expr_HdlSome_89, UInt<1>(1)), 2) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_89, _cast_enum_to_bits_expr_19), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_1.`1`)) + connect child_out.struct_opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 17:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty5 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_no_body = simplify_enums(m, SimplifyEnumsKind::SimplifyToEnumsWithNoBody).unwrap(); + dbg!(m_no_body); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_no_body => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {|HdlNone, HdlSome|} + type Ty1 = {tag: Ty0, body: UInt<0>} + type Ty2 = {tag: Ty0, body: UInt<1>} + type Ty3 = {`0`: Ty2, `1`: UInt<1>} + type Ty4 = {flip opt_unit_flip: Ty1, opt_unit: Ty1, flip opt_bool_flip: Ty2, opt_bool: Ty2, flip opt_opt_unit_flip: Ty2, opt_opt_unit: Ty2, flip array_opt_bool_flip: Ty2[2], array_opt_bool: Ty2[2], flip struct_opt_bool_flip: Ty3, struct_opt_bool: Ty3} + type Ty5 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty6 = {} + type Ty7 = {tag: UInt<1>, body: UInt<0>} + type Ty8 = {tag: UInt<1>, body: UInt<1>} + type Ty9 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty10 = {io: Ty4} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty4 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty4 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty4 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty5 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty5 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty5 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty5 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty5 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty1 + connect _bundle_literal_expr.tag, {|HdlNone, HdlSome|}(HdlSome) + wire _bundle_literal_expr_1: Ty6 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + connect io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr: UInt<1> + match io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr, UInt<1>(1) + wire _cast_enum_to_bits_expr_1: UInt<1> + match _bundle_literal_expr.tag: + HdlNone: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_1, UInt<1>(1) + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1), eq(io.opt_unit.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit, _bundle_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_2: UInt<1> + match io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_2, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_2, UInt<1>(1) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(_cast_enum_to_bits_expr_2, _cast_enum_to_bits_expr_1), eq(io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty2 + connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + connect io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_3: UInt<1> + match io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_3, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_3, UInt<1>(1) + wire _cast_enum_to_bits_expr_4: UInt<1> + match _bundle_literal_expr_2.tag: + HdlNone: + connect _cast_enum_to_bits_expr_4, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_4, UInt<1>(1) + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(_cast_enum_to_bits_expr_3, _cast_enum_to_bits_expr_4), eq(io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect parent_out.opt_bool_flip, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty2 + connect _bundle_literal_expr_3.tag, {|HdlNone, HdlSome|}(HdlSome) + wire _cast_bundle_to_bits_expr: Ty7 + connect _cast_bundle_to_bits_expr.tag, _cast_enum_to_bits_expr_1 + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + connect io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_5: UInt<1> + match io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_5, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_5, UInt<1>(1) + wire _cast_enum_to_bits_expr_6: UInt<1> + match _bundle_literal_expr_3.tag: + HdlNone: + connect _cast_enum_to_bits_expr_6, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_6, UInt<1>(1) + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(_cast_enum_to_bits_expr_5, _cast_enum_to_bits_expr_6), eq(io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect parent_out.opt_opt_unit_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty2[2] + wire _bundle_literal_expr_4: Ty2 + connect _bundle_literal_expr_4.tag, {|HdlNone, HdlSome|}(HdlSome) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + connect _array_literal_expr[0], _bundle_literal_expr_4 + connect _array_literal_expr[1], _bundle_literal_expr_2 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_2, __enum_structural_eq_3) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_7: UInt<1> + match io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_7, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_7, UInt<1>(1) + wire _cast_enum_to_bits_expr_8: UInt<1> + match _array_literal_expr[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_8, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_8, UInt<1>(1) + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(_cast_enum_to_bits_expr_7, _cast_enum_to_bits_expr_8), eq(io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_9: UInt<1> + match io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_9, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_9, UInt<1>(1) + wire _cast_enum_to_bits_expr_10: UInt<1> + match _array_literal_expr[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_10, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_10, UInt<1>(1) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(_cast_enum_to_bits_expr_9, _cast_enum_to_bits_expr_10), eq(io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect parent_out.array_opt_bool_flip, and(_bundle_structural_eq_4, _bundle_structural_eq_5) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty3 + connect _bundle_literal_expr_5.`0`, _bundle_literal_expr_2 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_4, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_11: UInt<1> + match io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_11, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_11, UInt<1>(1) + wire _cast_enum_to_bits_expr_12: UInt<1> + match _bundle_literal_expr_5.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_12, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_12, UInt<1>(1) + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(_cast_enum_to_bits_expr_11, _cast_enum_to_bits_expr_12), eq(io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect parent_out.struct_opt_bool_flip, and(_bundle_structural_eq_6, eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_bundle_expr: Ty1 + wire _cast_bits_to_bundle_expr_flattened: Ty7 + connect _cast_bits_to_bundle_expr_flattened.tag, bits(UInt<1>(0h0), 0, 0) + wire _cast_bits_to_enum_expr: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened.tag, 0)): + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr.tag, _cast_bits_to_enum_expr + connect _cast_bits_to_bundle_expr_flattened.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr.body, _cast_bits_to_bundle_expr_flattened.body + connect io_zeros.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_13: UInt<1> + match io_zeros.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_13, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_13, UInt<1>(1) + wire _cast_enum_to_bits_expr_14: UInt<1> + match _cast_bits_to_bundle_expr.tag: + HdlNone: + connect _cast_enum_to_bits_expr_14, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_14, UInt<1>(1) + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(_cast_enum_to_bits_expr_13, _cast_enum_to_bits_expr_14), eq(io_zeros.opt_unit.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_15: UInt<1> + match io_zeros.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_15, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_15, UInt<1>(1) + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(_cast_enum_to_bits_expr_15, _cast_enum_to_bits_expr_14), eq(io_zeros.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit_flip, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_1: Ty2 + wire _cast_bits_to_bundle_expr_flattened_1: Ty8 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(UInt<2>(0h0), 0, 0) + wire _cast_bits_to_enum_expr_1: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1 + connect _cast_bits_to_bundle_expr_flattened_1.body, bits(UInt<2>(0h0), 1, 1) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect io_zeros.opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_5 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_16: UInt<1> + match io_zeros.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_16, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_16, UInt<1>(1) + wire _cast_enum_to_bits_expr_17: UInt<1> + match _cast_bits_to_bundle_expr_1.tag: + HdlNone: + connect _cast_enum_to_bits_expr_17, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_17, UInt<1>(1) + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(_cast_enum_to_bits_expr_16, _cast_enum_to_bits_expr_17), eq(io_zeros.opt_bool_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_18: UInt<1> + match io_zeros.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_18, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_18, UInt<1>(1) + wire _bundle_structural_eq_10: UInt<1> + connect _bundle_structural_eq_10, and(eq(_cast_enum_to_bits_expr_18, _cast_enum_to_bits_expr_17), eq(io_zeros.opt_opt_unit_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_opt_unit_flip, _bundle_structural_eq_10 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty2[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_2: Ty2 + wire _cast_bits_to_bundle_expr_flattened_2: Ty8 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(_cast_bits_to_array_expr_flattened[0], 0, 0) + wire _cast_bits_to_enum_expr_2: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(_cast_bits_to_array_expr_flattened[0], 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + connect _cast_bits_to_array_expr[0], _cast_bits_to_bundle_expr_2 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_bundle_expr_3: Ty2 + wire _cast_bits_to_bundle_expr_flattened_3: Ty8 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(_cast_bits_to_array_expr_flattened[1], 0, 0) + wire _cast_bits_to_enum_expr_3: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 + connect _cast_bits_to_bundle_expr_flattened_3.body, bits(_cast_bits_to_array_expr_flattened[1], 1, 1) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect _cast_bits_to_array_expr[1], _cast_bits_to_bundle_expr_3 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_7, __enum_structural_eq_8) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_19: UInt<1> + match io_zeros.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_19, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_19, UInt<1>(1) + wire _cast_enum_to_bits_expr_20: UInt<1> + match _cast_bits_to_array_expr[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_20, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_20, UInt<1>(1) + wire _bundle_structural_eq_11: UInt<1> + connect _bundle_structural_eq_11, and(eq(_cast_enum_to_bits_expr_19, _cast_enum_to_bits_expr_20), eq(io_zeros.array_opt_bool_flip[0].body, _cast_bits_to_array_expr[0].body)) + wire _cast_enum_to_bits_expr_21: UInt<1> + match io_zeros.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_21, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_21, UInt<1>(1) + wire _cast_enum_to_bits_expr_22: UInt<1> + match _cast_bits_to_array_expr[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_22, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_22, UInt<1>(1) + wire _bundle_structural_eq_12: UInt<1> + connect _bundle_structural_eq_12, and(eq(_cast_enum_to_bits_expr_21, _cast_enum_to_bits_expr_22), eq(io_zeros.array_opt_bool_flip[1].body, _cast_bits_to_array_expr[1].body)) + connect parent_zeros_out.array_opt_bool_flip, and(_bundle_structural_eq_11, _bundle_structural_eq_12) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_4: Ty3 + wire _cast_bits_to_bundle_expr_flattened_4: Ty9 + connect _cast_bits_to_bundle_expr_flattened_4.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_5: Ty2 + wire _cast_bits_to_bundle_expr_flattened_5: Ty8 + connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 0, 0) + wire _cast_bits_to_enum_expr_4: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)): + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_4 + connect _cast_bits_to_bundle_expr_flattened_5.body, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body + connect _cast_bits_to_bundle_expr_4.`0`, _cast_bits_to_bundle_expr_5 + connect _cast_bits_to_bundle_expr_flattened_4.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_4.`1`, _cast_bits_to_bundle_expr_flattened_4.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_4 @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_9, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_23: UInt<1> + match io_zeros.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_23, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_23, UInt<1>(1) + wire _cast_enum_to_bits_expr_24: UInt<1> + match _cast_bits_to_bundle_expr_4.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_24, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_24, UInt<1>(1) + wire _bundle_structural_eq_13: UInt<1> + connect _bundle_structural_eq_13, and(eq(_cast_enum_to_bits_expr_23, _cast_enum_to_bits_expr_24), eq(io_zeros.struct_opt_bool_flip.`0`.body, _cast_bits_to_bundle_expr_4.`0`.body)) + connect parent_zeros_out.struct_opt_bool_flip, and(_bundle_structural_eq_13, eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_25: UInt<1> + match io_alternating.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_25, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_25, UInt<1>(1) + wire _bundle_structural_eq_14: UInt<1> + connect _bundle_structural_eq_14, and(eq(_cast_enum_to_bits_expr_25, _cast_enum_to_bits_expr_14), eq(io_alternating.opt_unit.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit, _bundle_structural_eq_14 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_26: UInt<1> + match io_alternating.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_26, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_26, UInt<1>(1) + wire _bundle_structural_eq_15: UInt<1> + connect _bundle_structural_eq_15, and(eq(_cast_enum_to_bits_expr_26, _cast_enum_to_bits_expr_14), eq(io_alternating.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit_flip, _bundle_structural_eq_15 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_6: Ty2 + wire _cast_bits_to_bundle_expr_flattened_6: Ty8 + connect _cast_bits_to_bundle_expr_flattened_6.tag, bits(UInt<2>(0h2), 0, 0) + wire _cast_bits_to_enum_expr_5: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_6.tag, 0)): + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_6.tag, _cast_bits_to_enum_expr_5 + connect _cast_bits_to_bundle_expr_flattened_6.body, bits(UInt<2>(0h2), 1, 1) + connect _cast_bits_to_bundle_expr_6.body, _cast_bits_to_bundle_expr_flattened_6.body + connect io_alternating.opt_bool_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_10 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_11 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty2[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_bundle_expr_7: Ty2 + wire _cast_bits_to_bundle_expr_flattened_7: Ty8 + connect _cast_bits_to_bundle_expr_flattened_7.tag, bits(_cast_bits_to_array_expr_flattened_1[0], 0, 0) + wire _cast_bits_to_enum_expr_6: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_7.tag, 0)): + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_6, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_7.tag, _cast_bits_to_enum_expr_6 + connect _cast_bits_to_bundle_expr_flattened_7.body, bits(_cast_bits_to_array_expr_flattened_1[0], 1, 1) + connect _cast_bits_to_bundle_expr_7.body, _cast_bits_to_bundle_expr_flattened_7.body + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_bundle_expr_7 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_bundle_expr_8: Ty2 + wire _cast_bits_to_bundle_expr_flattened_8: Ty8 + connect _cast_bits_to_bundle_expr_flattened_8.tag, bits(_cast_bits_to_array_expr_flattened_1[1], 0, 0) + wire _cast_bits_to_enum_expr_7: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_8.tag, 0)): + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_7, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_8.tag, _cast_bits_to_enum_expr_7 + connect _cast_bits_to_bundle_expr_flattened_8.body, bits(_cast_bits_to_array_expr_flattened_1[1], 1, 1) + connect _cast_bits_to_bundle_expr_8.body, _cast_bits_to_bundle_expr_flattened_8.body + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_bundle_expr_8 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_14, __enum_structural_eq_15) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_16, __enum_structural_eq_17) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_9: Ty3 + wire _cast_bits_to_bundle_expr_flattened_9: Ty9 + connect _cast_bits_to_bundle_expr_flattened_9.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_bundle_expr_10: Ty2 + wire _cast_bits_to_bundle_expr_flattened_10: Ty8 + connect _cast_bits_to_bundle_expr_flattened_10.tag, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 0, 0) + wire _cast_bits_to_enum_expr_8: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_10.tag, 0)): + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_8, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_10.tag, _cast_bits_to_enum_expr_8 + connect _cast_bits_to_bundle_expr_flattened_10.body, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_10.body, _cast_bits_to_bundle_expr_flattened_10.body + connect _cast_bits_to_bundle_expr_9.`0`, _cast_bits_to_bundle_expr_10 + connect _cast_bits_to_bundle_expr_flattened_9.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_9.`1`, _cast_bits_to_bundle_expr_flattened_9.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_9 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_18, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_19, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_27: UInt<1> + match extern_child.io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_27, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_27, UInt<1>(1) + wire _bundle_structural_eq_16: UInt<1> + connect _bundle_structural_eq_16, and(eq(_cast_enum_to_bits_expr_27, _cast_enum_to_bits_expr_1), eq(extern_child.io.opt_unit.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit, _bundle_structural_eq_16 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_28: UInt<1> + match extern_child.io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_28, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_28, UInt<1>(1) + wire _bundle_structural_eq_17: UInt<1> + connect _bundle_structural_eq_17, and(eq(_cast_enum_to_bits_expr_28, _cast_enum_to_bits_expr_1), eq(extern_child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit_flip, _bundle_structural_eq_17 @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_20 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_29: UInt<1> + match extern_child.io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_29, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_29, UInt<1>(1) + wire _bundle_structural_eq_18: UInt<1> + connect _bundle_structural_eq_18, and(eq(_cast_enum_to_bits_expr_29, _cast_enum_to_bits_expr_4), eq(extern_child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect extern_child_out.opt_bool_flip, _bundle_structural_eq_18 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_21 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_30: UInt<1> + match extern_child.io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_30, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_30, UInt<1>(1) + wire _bundle_structural_eq_19: UInt<1> + connect _bundle_structural_eq_19, and(eq(_cast_enum_to_bits_expr_30, _cast_enum_to_bits_expr_6), eq(extern_child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect extern_child_out.opt_opt_unit_flip, _bundle_structural_eq_19 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_22, __enum_structural_eq_23) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_31: UInt<1> + match extern_child.io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_31, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_31, UInt<1>(1) + wire _bundle_structural_eq_20: UInt<1> + connect _bundle_structural_eq_20, and(eq(_cast_enum_to_bits_expr_31, _cast_enum_to_bits_expr_8), eq(extern_child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_32: UInt<1> + match extern_child.io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_32, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_32, UInt<1>(1) + wire _bundle_structural_eq_21: UInt<1> + connect _bundle_structural_eq_21, and(eq(_cast_enum_to_bits_expr_32, _cast_enum_to_bits_expr_10), eq(extern_child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect extern_child_out.array_opt_bool_flip, and(_bundle_structural_eq_20, _bundle_structural_eq_21) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_24, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_33: UInt<1> + match extern_child.io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_33, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_33, UInt<1>(1) + wire _bundle_structural_eq_22: UInt<1> + connect _bundle_structural_eq_22, and(eq(_cast_enum_to_bits_expr_33, _cast_enum_to_bits_expr_12), eq(extern_child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect extern_child_out.struct_opt_bool_flip, and(_bundle_structural_eq_22, eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_34: UInt<1> + match child.io.opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_34, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_34, UInt<1>(1) + wire _bundle_structural_eq_23: UInt<1> + connect _bundle_structural_eq_23, and(eq(_cast_enum_to_bits_expr_34, _cast_enum_to_bits_expr_1), eq(child.io.opt_unit.body, _bundle_literal_expr.body)) + connect child_out.opt_unit, _bundle_structural_eq_23 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_enum_to_bits_expr_35: UInt<1> + match child.io.opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_35, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_35, UInt<1>(1) + wire _bundle_structural_eq_24: UInt<1> + connect _bundle_structural_eq_24, and(eq(_cast_enum_to_bits_expr_35, _cast_enum_to_bits_expr_1), eq(child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect child_out.opt_unit_flip, _bundle_structural_eq_24 @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_36: UInt<1> + match child.io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_36, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_36, UInt<1>(1) + wire _bundle_structural_eq_25: UInt<1> + connect _bundle_structural_eq_25, and(eq(_cast_enum_to_bits_expr_36, _cast_enum_to_bits_expr_4), eq(child.io.opt_bool.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool, _bundle_structural_eq_25 @[module-XXXXXXXXXX.rs 14:1] + wire _cast_enum_to_bits_expr_37: UInt<1> + match child.io.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_37, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_37, UInt<1>(1) + wire _bundle_structural_eq_26: UInt<1> + connect _bundle_structural_eq_26, and(eq(_cast_enum_to_bits_expr_37, _cast_enum_to_bits_expr_4), eq(child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool_flip, _bundle_structural_eq_26 @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_38: UInt<1> + match child.io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_38, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_38, UInt<1>(1) + wire _bundle_structural_eq_27: UInt<1> + connect _bundle_structural_eq_27, and(eq(_cast_enum_to_bits_expr_38, _cast_enum_to_bits_expr_6), eq(child.io.opt_opt_unit.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit, _bundle_structural_eq_27 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_enum_to_bits_expr_39: UInt<1> + match child.io.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_39, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_39, UInt<1>(1) + wire _bundle_structural_eq_28: UInt<1> + connect _bundle_structural_eq_28, and(eq(_cast_enum_to_bits_expr_39, _cast_enum_to_bits_expr_6), eq(child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit_flip, _bundle_structural_eq_28 @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_40: UInt<1> + match child.io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_40, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_40, UInt<1>(1) + wire _bundle_structural_eq_29: UInt<1> + connect _bundle_structural_eq_29, and(eq(_cast_enum_to_bits_expr_40, _cast_enum_to_bits_expr_8), eq(child.io.array_opt_bool[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_41: UInt<1> + match child.io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_41, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_41, UInt<1>(1) + wire _bundle_structural_eq_30: UInt<1> + connect _bundle_structural_eq_30, and(eq(_cast_enum_to_bits_expr_41, _cast_enum_to_bits_expr_10), eq(child.io.array_opt_bool[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool, and(_bundle_structural_eq_29, _bundle_structural_eq_30) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_enum_to_bits_expr_42: UInt<1> + match child.io.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_42, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_42, UInt<1>(1) + wire _bundle_structural_eq_31: UInt<1> + connect _bundle_structural_eq_31, and(eq(_cast_enum_to_bits_expr_42, _cast_enum_to_bits_expr_8), eq(child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _cast_enum_to_bits_expr_43: UInt<1> + match child.io.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_43, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_43, UInt<1>(1) + wire _bundle_structural_eq_32: UInt<1> + connect _bundle_structural_eq_32, and(eq(_cast_enum_to_bits_expr_43, _cast_enum_to_bits_expr_10), eq(child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool_flip, and(_bundle_structural_eq_31, _bundle_structural_eq_32) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_44: UInt<1> + match child.io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_44, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_44, UInt<1>(1) + wire _bundle_structural_eq_33: UInt<1> + connect _bundle_structural_eq_33, and(eq(_cast_enum_to_bits_expr_44, _cast_enum_to_bits_expr_12), eq(child.io.struct_opt_bool.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool, and(_bundle_structural_eq_33, eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_enum_to_bits_expr_45: UInt<1> + match child.io.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_45, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_45, UInt<1>(1) + wire _bundle_structural_eq_34: UInt<1> + connect _bundle_structural_eq_34, and(eq(_cast_enum_to_bits_expr_45, _cast_enum_to_bits_expr_12), eq(child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool_flip, and(_bundle_structural_eq_34, eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_46: UInt<1> + match io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_46, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_46, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_46, _cast_enum_to_bits_expr_4): @[module-XXXXXXXXXX.rs 1:1] + match io.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq, eq(bits(io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_47: UInt<1> + match io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_47, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_47, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_47, _cast_enum_to_bits_expr_6): @[module-XXXXXXXXXX.rs 1:1] + match io.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_11: Ty1 + wire _cast_bits_to_bundle_expr_flattened_11: Ty7 + connect _cast_bits_to_bundle_expr_flattened_11.tag, bits(bits(io.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_9: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_11.tag, 0)): + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_9, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_11.tag, _cast_bits_to_enum_expr_9 + connect _cast_bits_to_bundle_expr_flattened_11.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_11.body, _cast_bits_to_bundle_expr_flattened_11.body + wire _cast_bits_to_bundle_expr_12: Ty1 + wire _cast_bits_to_bundle_expr_flattened_12: Ty7 + connect _cast_bits_to_bundle_expr_flattened_12.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_10: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_12.tag, 0)): + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_10, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_12.tag, _cast_bits_to_enum_expr_10 + connect _cast_bits_to_bundle_expr_flattened_12.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_12.body, _cast_bits_to_bundle_expr_flattened_12.body + wire _cast_enum_to_bits_expr_48: UInt<1> + match _cast_bits_to_bundle_expr_11.tag: + HdlNone: + connect _cast_enum_to_bits_expr_48, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_48, UInt<1>(1) + wire _cast_enum_to_bits_expr_49: UInt<1> + match _cast_bits_to_bundle_expr_12.tag: + HdlNone: + connect _cast_enum_to_bits_expr_49, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_49, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_48, _cast_enum_to_bits_expr_49): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_11.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_13: Ty6 + invalidate _cast_bits_to_bundle_expr_13 + wire _cast_bits_to_bundle_expr_14: Ty6 + invalidate _cast_bits_to_bundle_expr_14 + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_50: UInt<1> + match io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_50, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_50, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_50, _cast_enum_to_bits_expr_8): @[module-XXXXXXXXXX.rs 1:1] + match io.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_2, eq(bits(io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_51: UInt<1> + match io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_51, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_51, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_51, _cast_enum_to_bits_expr_10): @[module-XXXXXXXXXX.rs 1:1] + match io.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_3, eq(bits(io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_52: UInt<1> + match io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_52, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_52, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_52, _cast_enum_to_bits_expr_12): @[module-XXXXXXXXXX.rs 1:1] + match io.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_4, eq(bits(io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_53: UInt<1> + match io_zeros.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_53, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_53, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_53, _cast_enum_to_bits_expr_17): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_5, eq(bits(io_zeros.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_1.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_54: UInt<1> + match io_zeros.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_54, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_54, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_54, _cast_enum_to_bits_expr_17): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, __enum_structural_eq_26 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_15: Ty1 + wire _cast_bits_to_bundle_expr_flattened_13: Ty7 + connect _cast_bits_to_bundle_expr_flattened_13.tag, bits(bits(io_zeros.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_11: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_13.tag, 0)): + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_11, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_15.tag, _cast_bits_to_enum_expr_11 + connect _cast_bits_to_bundle_expr_flattened_13.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_15.body, _cast_bits_to_bundle_expr_flattened_13.body + wire _cast_bits_to_bundle_expr_16: Ty1 + wire _cast_bits_to_bundle_expr_flattened_14: Ty7 + connect _cast_bits_to_bundle_expr_flattened_14.tag, bits(bits(_cast_bits_to_bundle_expr_1.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_12: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_14.tag, 0)): + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_12, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_16.tag, _cast_bits_to_enum_expr_12 + connect _cast_bits_to_bundle_expr_flattened_14.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_16.body, _cast_bits_to_bundle_expr_flattened_14.body + wire _cast_enum_to_bits_expr_55: UInt<1> + match _cast_bits_to_bundle_expr_15.tag: + HdlNone: + connect _cast_enum_to_bits_expr_55, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_55, UInt<1>(1) + wire _cast_enum_to_bits_expr_56: UInt<1> + match _cast_bits_to_bundle_expr_16.tag: + HdlNone: + connect _cast_enum_to_bits_expr_56, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_56, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_55, _cast_enum_to_bits_expr_56): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_15.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_17: Ty6 + invalidate _cast_bits_to_bundle_expr_17 + wire _cast_bits_to_bundle_expr_18: Ty6 + invalidate _cast_bits_to_bundle_expr_18 + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_57: UInt<1> + match io_zeros.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_57, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_57, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_57, _cast_enum_to_bits_expr_20): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_7, eq(bits(io_zeros.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_58: UInt<1> + match io_zeros.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_58, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_58, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_58, _cast_enum_to_bits_expr_22): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_8, eq(bits(io_zeros.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_59: UInt<1> + match io_zeros.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_59, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_59, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_59, _cast_enum_to_bits_expr_24): @[module-XXXXXXXXXX.rs 1:1] + match io_zeros.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_9, eq(bits(io_zeros.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_4.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_60: UInt<1> + match io_alternating.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_60, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_60, UInt<1>(1) + wire _cast_enum_to_bits_expr_61: UInt<1> + match _cast_bits_to_bundle_expr_6.tag: + HdlNone: + connect _cast_enum_to_bits_expr_61, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_61, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_60, _cast_enum_to_bits_expr_61): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_10, eq(bits(io_alternating.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_62: UInt<1> + match io_alternating.opt_bool_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_62, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_62, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_62, _cast_enum_to_bits_expr_61): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_bool_flip.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_11, eq(bits(io_alternating.opt_bool_flip.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_63: UInt<1> + match io_alternating.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_63, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_63, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_63, _cast_enum_to_bits_expr_61): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, __enum_structural_eq_27 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_19: Ty1 + wire _cast_bits_to_bundle_expr_flattened_15: Ty7 + connect _cast_bits_to_bundle_expr_flattened_15.tag, bits(bits(io_alternating.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_13: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_15.tag, 0)): + connect _cast_bits_to_enum_expr_13, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_13, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_19.tag, _cast_bits_to_enum_expr_13 + connect _cast_bits_to_bundle_expr_flattened_15.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_19.body, _cast_bits_to_bundle_expr_flattened_15.body + wire _cast_bits_to_bundle_expr_20: Ty1 + wire _cast_bits_to_bundle_expr_flattened_16: Ty7 + connect _cast_bits_to_bundle_expr_flattened_16.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_14: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_16.tag, 0)): + connect _cast_bits_to_enum_expr_14, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_14, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_20.tag, _cast_bits_to_enum_expr_14 + connect _cast_bits_to_bundle_expr_flattened_16.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_20.body, _cast_bits_to_bundle_expr_flattened_16.body + wire _cast_enum_to_bits_expr_64: UInt<1> + match _cast_bits_to_bundle_expr_19.tag: + HdlNone: + connect _cast_enum_to_bits_expr_64, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_64, UInt<1>(1) + wire _cast_enum_to_bits_expr_65: UInt<1> + match _cast_bits_to_bundle_expr_20.tag: + HdlNone: + connect _cast_enum_to_bits_expr_65, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_65, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_64, _cast_enum_to_bits_expr_65): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_19.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_21: Ty6 + invalidate _cast_bits_to_bundle_expr_21 + wire _cast_bits_to_bundle_expr_22: Ty6 + invalidate _cast_bits_to_bundle_expr_22 + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_66: UInt<1> + match io_alternating.opt_opt_unit_flip.tag: + HdlNone: + connect _cast_enum_to_bits_expr_66, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_66, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_66, _cast_enum_to_bits_expr_61): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.opt_opt_unit_flip.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, __enum_structural_eq_28 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_23: Ty1 + wire _cast_bits_to_bundle_expr_flattened_17: Ty7 + connect _cast_bits_to_bundle_expr_flattened_17.tag, bits(bits(io_alternating.opt_opt_unit_flip.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_15: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_17.tag, 0)): + connect _cast_bits_to_enum_expr_15, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_15, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_23.tag, _cast_bits_to_enum_expr_15 + connect _cast_bits_to_bundle_expr_flattened_17.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_23.body, _cast_bits_to_bundle_expr_flattened_17.body + wire _cast_bits_to_bundle_expr_24: Ty1 + wire _cast_bits_to_bundle_expr_flattened_18: Ty7 + connect _cast_bits_to_bundle_expr_flattened_18.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_16: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_18.tag, 0)): + connect _cast_bits_to_enum_expr_16, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_16, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_24.tag, _cast_bits_to_enum_expr_16 + connect _cast_bits_to_bundle_expr_flattened_18.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_24.body, _cast_bits_to_bundle_expr_flattened_18.body + wire _cast_enum_to_bits_expr_67: UInt<1> + match _cast_bits_to_bundle_expr_23.tag: + HdlNone: + connect _cast_enum_to_bits_expr_67, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_67, UInt<1>(1) + wire _cast_enum_to_bits_expr_68: UInt<1> + match _cast_bits_to_bundle_expr_24.tag: + HdlNone: + connect _cast_enum_to_bits_expr_68, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_68, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_67, _cast_enum_to_bits_expr_68): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_23.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_25: Ty6 + invalidate _cast_bits_to_bundle_expr_25 + wire _cast_bits_to_bundle_expr_26: Ty6 + invalidate _cast_bits_to_bundle_expr_26 + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_69: UInt<1> + match io_alternating.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_69, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_69, UInt<1>(1) + wire _cast_enum_to_bits_expr_70: UInt<1> + match _cast_bits_to_array_expr_1[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_70, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_70, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_69, _cast_enum_to_bits_expr_70): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_14, eq(bits(io_alternating.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_71: UInt<1> + match io_alternating.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_71, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_71, UInt<1>(1) + wire _cast_enum_to_bits_expr_72: UInt<1> + match _cast_bits_to_array_expr_1[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_72, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_72, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_71, _cast_enum_to_bits_expr_72): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_15, eq(bits(io_alternating.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_73: UInt<1> + match io_alternating.array_opt_bool_flip[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_73, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_73, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_73, _cast_enum_to_bits_expr_70): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool_flip[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_16, eq(bits(io_alternating.array_opt_bool_flip[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_74: UInt<1> + match io_alternating.array_opt_bool_flip[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_74, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_74, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_74, _cast_enum_to_bits_expr_72): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.array_opt_bool_flip[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_17, eq(bits(io_alternating.array_opt_bool_flip[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_75: UInt<1> + match io_alternating.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_75, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_75, UInt<1>(1) + wire _cast_enum_to_bits_expr_76: UInt<1> + match _cast_bits_to_bundle_expr_9.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_76, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_76, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_75, _cast_enum_to_bits_expr_76): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_18, eq(bits(io_alternating.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_77: UInt<1> + match io_alternating.struct_opt_bool_flip.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_77, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_77, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_77, _cast_enum_to_bits_expr_76): @[module-XXXXXXXXXX.rs 1:1] + match io_alternating.struct_opt_bool_flip.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_19, eq(bits(io_alternating.struct_opt_bool_flip.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_78: UInt<1> + match extern_child.io.opt_bool.tag: + HdlNone: + connect _cast_enum_to_bits_expr_78, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_78, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_78, _cast_enum_to_bits_expr_4): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.opt_bool.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_20, eq(bits(extern_child.io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_79: UInt<1> + match extern_child.io.opt_opt_unit.tag: + HdlNone: + connect _cast_enum_to_bits_expr_79, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_79, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_79, _cast_enum_to_bits_expr_6): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.opt_opt_unit.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_27: Ty1 + wire _cast_bits_to_bundle_expr_flattened_19: Ty7 + connect _cast_bits_to_bundle_expr_flattened_19.tag, bits(bits(extern_child.io.opt_opt_unit.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_17: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_19.tag, 0)): + connect _cast_bits_to_enum_expr_17, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_17, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_27.tag, _cast_bits_to_enum_expr_17 + connect _cast_bits_to_bundle_expr_flattened_19.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_27.body, _cast_bits_to_bundle_expr_flattened_19.body + wire _cast_bits_to_bundle_expr_28: Ty1 + wire _cast_bits_to_bundle_expr_flattened_20: Ty7 + connect _cast_bits_to_bundle_expr_flattened_20.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_18: Ty0 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_20.tag, 0)): + connect _cast_bits_to_enum_expr_18, {|HdlNone, HdlSome|}(HdlNone) + else: + connect _cast_bits_to_enum_expr_18, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_28.tag, _cast_bits_to_enum_expr_18 + connect _cast_bits_to_bundle_expr_flattened_20.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_28.body, _cast_bits_to_bundle_expr_flattened_20.body + wire _cast_enum_to_bits_expr_80: UInt<1> + match _cast_bits_to_bundle_expr_27.tag: + HdlNone: + connect _cast_enum_to_bits_expr_80, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_80, UInt<1>(1) + wire _cast_enum_to_bits_expr_81: UInt<1> + match _cast_bits_to_bundle_expr_28.tag: + HdlNone: + connect _cast_enum_to_bits_expr_81, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_81, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_80, _cast_enum_to_bits_expr_81): @[module-XXXXXXXXXX.rs 1:1] + match _cast_bits_to_bundle_expr_27.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + wire _cast_bits_to_bundle_expr_29: Ty6 + invalidate _cast_bits_to_bundle_expr_29 + wire _cast_bits_to_bundle_expr_30: Ty6 + invalidate _cast_bits_to_bundle_expr_30 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_82: UInt<1> + match extern_child.io.array_opt_bool[0].tag: + HdlNone: + connect _cast_enum_to_bits_expr_82, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_82, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_82, _cast_enum_to_bits_expr_8): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.array_opt_bool[0].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_22, eq(bits(extern_child.io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_83: UInt<1> + match extern_child.io.array_opt_bool[1].tag: + HdlNone: + connect _cast_enum_to_bits_expr_83, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_83, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_83, _cast_enum_to_bits_expr_10): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.array_opt_bool[1].tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_23, eq(bits(extern_child.io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr_84: UInt<1> + match extern_child.io.struct_opt_bool.`0`.tag: + HdlNone: + connect _cast_enum_to_bits_expr_84, UInt<1>(0) + HdlSome: + connect _cast_enum_to_bits_expr_84, UInt<1>(1) + when eq(_cast_enum_to_bits_expr_84, _cast_enum_to_bits_expr_12): @[module-XXXXXXXXXX.rs 1:1] + match extern_child.io.struct_opt_bool.`0`.tag: @[module-XXXXXXXXXX.rs 1:1] + HdlNone: + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + HdlSome: + connect __enum_structural_eq_24, eq(bits(extern_child.io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty4 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty4 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_bundle_of_uints = simplify_enums(m, SimplifyEnumsKind::ReplaceWithBundleOfUInts).unwrap(); + dbg!(m_bundle_of_uints); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_bundle_of_uints => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {tag: UInt<1>, body: UInt<0>} + type Ty1 = {tag: UInt<1>, body: UInt<1>} + type Ty2 = {`0`: Ty1, `1`: UInt<1>} + type Ty3 = {flip opt_unit_flip: Ty0, opt_unit: Ty0, flip opt_bool_flip: Ty1, opt_bool: Ty1, flip opt_opt_unit_flip: Ty1, opt_opt_unit: Ty1, flip array_opt_bool_flip: Ty1[2], array_opt_bool: Ty1[2], flip struct_opt_bool_flip: Ty2, struct_opt_bool: Ty2} + type Ty4 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty5 = {} + type Ty6 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty7 = {io: Ty3} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty3 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty3 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty3 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty4 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty4 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty4 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty4 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty4 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty0 + connect _bundle_literal_expr.tag, UInt<1>(0h1) + wire _bundle_literal_expr_1: Ty5 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + connect io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(io.opt_unit.tag, _bundle_literal_expr.tag), eq(io.opt_unit.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit, _bundle_structural_eq @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(eq(io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect parent_out.opt_unit_flip, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty1 + connect _bundle_literal_expr_2.tag, UInt<1>(0h1) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + connect io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, and(eq(io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect parent_out.opt_bool_flip, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty1 + connect _bundle_literal_expr_3.tag, UInt<1>(0h1) + wire _cast_bundle_to_bits_expr: Ty0 + connect _cast_bundle_to_bits_expr.tag, _bundle_literal_expr.tag + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + connect io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_3: UInt<1> + connect _bundle_structural_eq_3, and(eq(io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect parent_out.opt_opt_unit_flip, _bundle_structural_eq_3 @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: Ty1[2] + wire _bundle_literal_expr_4: Ty1 + connect _bundle_literal_expr_4.tag, UInt<1>(0h1) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + connect _array_literal_expr[0], _bundle_literal_expr_4 + connect _array_literal_expr[1], _bundle_literal_expr_2 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_2, __enum_structural_eq_3) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_4: UInt<1> + connect _bundle_structural_eq_4, and(eq(io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_5: UInt<1> + connect _bundle_structural_eq_5, and(eq(io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect parent_out.array_opt_bool_flip, and(_bundle_structural_eq_4, _bundle_structural_eq_5) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty2 + connect _bundle_literal_expr_5.`0`, _bundle_literal_expr_2 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_4, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_6: UInt<1> + connect _bundle_structural_eq_6, and(eq(io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect parent_out.struct_opt_bool_flip, and(_bundle_structural_eq_6, eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _cast_bits_to_bundle_expr: Ty0 + wire _cast_bits_to_bundle_expr_flattened: Ty0 + connect _cast_bits_to_bundle_expr_flattened.tag, bits(UInt<1>(0h0), 0, 0) + connect _cast_bits_to_bundle_expr.tag, _cast_bits_to_bundle_expr_flattened.tag + connect _cast_bits_to_bundle_expr_flattened.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr.body, _cast_bits_to_bundle_expr_flattened.body + connect io_zeros.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_7: UInt<1> + connect _bundle_structural_eq_7, and(eq(io_zeros.opt_unit.tag, _cast_bits_to_bundle_expr.tag), eq(io_zeros.opt_unit.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit, _bundle_structural_eq_7 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_8: UInt<1> + connect _bundle_structural_eq_8, and(eq(io_zeros.opt_unit_flip.tag, _cast_bits_to_bundle_expr.tag), eq(io_zeros.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_zeros_out.opt_unit_flip, _bundle_structural_eq_8 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_1: Ty1 + wire _cast_bits_to_bundle_expr_flattened_1: Ty1 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(UInt<2>(0h0), 0, 0) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag + connect _cast_bits_to_bundle_expr_flattened_1.body, bits(UInt<2>(0h0), 1, 1) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect io_zeros.opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_5 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_9: UInt<1> + connect _bundle_structural_eq_9, and(eq(io_zeros.opt_bool_flip.tag, _cast_bits_to_bundle_expr_1.tag), eq(io_zeros.opt_bool_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_bool_flip, _bundle_structural_eq_9 @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_10: UInt<1> + connect _bundle_structural_eq_10, and(eq(io_zeros.opt_opt_unit_flip.tag, _cast_bits_to_bundle_expr_1.tag), eq(io_zeros.opt_opt_unit_flip.body, _cast_bits_to_bundle_expr_1.body)) + connect parent_zeros_out.opt_opt_unit_flip, _bundle_structural_eq_10 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: Ty1[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_2: Ty1 + wire _cast_bits_to_bundle_expr_flattened_2: Ty1 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(_cast_bits_to_array_expr_flattened[0], 0, 0) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(_cast_bits_to_array_expr_flattened[0], 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + connect _cast_bits_to_array_expr[0], _cast_bits_to_bundle_expr_2 + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + wire _cast_bits_to_bundle_expr_3: Ty1 + wire _cast_bits_to_bundle_expr_flattened_3: Ty1 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(_cast_bits_to_array_expr_flattened[1], 0, 0) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag + connect _cast_bits_to_bundle_expr_flattened_3.body, bits(_cast_bits_to_array_expr_flattened[1], 1, 1) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect _cast_bits_to_array_expr[1], _cast_bits_to_bundle_expr_3 + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_7, __enum_structural_eq_8) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_11: UInt<1> + connect _bundle_structural_eq_11, and(eq(io_zeros.array_opt_bool_flip[0].tag, _cast_bits_to_array_expr[0].tag), eq(io_zeros.array_opt_bool_flip[0].body, _cast_bits_to_array_expr[0].body)) + wire _bundle_structural_eq_12: UInt<1> + connect _bundle_structural_eq_12, and(eq(io_zeros.array_opt_bool_flip[1].tag, _cast_bits_to_array_expr[1].tag), eq(io_zeros.array_opt_bool_flip[1].body, _cast_bits_to_array_expr[1].body)) + connect parent_zeros_out.array_opt_bool_flip, and(_bundle_structural_eq_11, _bundle_structural_eq_12) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_4: Ty2 + wire _cast_bits_to_bundle_expr_flattened_4: Ty6 + connect _cast_bits_to_bundle_expr_flattened_4.`0`, bits(UInt<3>(0h0), 1, 0) + wire _cast_bits_to_bundle_expr_5: Ty1 + wire _cast_bits_to_bundle_expr_flattened_5: Ty1 + connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 0, 0) + connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag + connect _cast_bits_to_bundle_expr_flattened_5.body, bits(_cast_bits_to_bundle_expr_flattened_4.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body + connect _cast_bits_to_bundle_expr_4.`0`, _cast_bits_to_bundle_expr_5 + connect _cast_bits_to_bundle_expr_flattened_4.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr_4.`1`, _cast_bits_to_bundle_expr_flattened_4.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr_4 @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_9, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_13: UInt<1> + connect _bundle_structural_eq_13, and(eq(io_zeros.struct_opt_bool_flip.`0`.tag, _cast_bits_to_bundle_expr_4.`0`.tag), eq(io_zeros.struct_opt_bool_flip.`0`.body, _cast_bits_to_bundle_expr_4.`0`.body)) + connect parent_zeros_out.struct_opt_bool_flip, and(_bundle_structural_eq_13, eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_4.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_14: UInt<1> + connect _bundle_structural_eq_14, and(eq(io_alternating.opt_unit.tag, _cast_bits_to_bundle_expr.tag), eq(io_alternating.opt_unit.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit, _bundle_structural_eq_14 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_15: UInt<1> + connect _bundle_structural_eq_15, and(eq(io_alternating.opt_unit_flip.tag, _cast_bits_to_bundle_expr.tag), eq(io_alternating.opt_unit_flip.body, _cast_bits_to_bundle_expr.body)) + connect parent_alternating_out.opt_unit_flip, _bundle_structural_eq_15 @[module-XXXXXXXXXX.rs 13:1] + wire _cast_bits_to_bundle_expr_6: Ty1 + wire _cast_bits_to_bundle_expr_flattened_6: Ty1 + connect _cast_bits_to_bundle_expr_flattened_6.tag, bits(UInt<2>(0h2), 0, 0) + connect _cast_bits_to_bundle_expr_6.tag, _cast_bits_to_bundle_expr_flattened_6.tag + connect _cast_bits_to_bundle_expr_flattened_6.body, bits(UInt<2>(0h2), 1, 1) + connect _cast_bits_to_bundle_expr_6.body, _cast_bits_to_bundle_expr_flattened_6.body + connect io_alternating.opt_bool_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_10 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_11 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, _cast_bits_to_bundle_expr_6 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: Ty1[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + wire _cast_bits_to_bundle_expr_7: Ty1 + wire _cast_bits_to_bundle_expr_flattened_7: Ty1 + connect _cast_bits_to_bundle_expr_flattened_7.tag, bits(_cast_bits_to_array_expr_flattened_1[0], 0, 0) + connect _cast_bits_to_bundle_expr_7.tag, _cast_bits_to_bundle_expr_flattened_7.tag + connect _cast_bits_to_bundle_expr_flattened_7.body, bits(_cast_bits_to_array_expr_flattened_1[0], 1, 1) + connect _cast_bits_to_bundle_expr_7.body, _cast_bits_to_bundle_expr_flattened_7.body + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_bundle_expr_7 + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + wire _cast_bits_to_bundle_expr_8: Ty1 + wire _cast_bits_to_bundle_expr_flattened_8: Ty1 + connect _cast_bits_to_bundle_expr_flattened_8.tag, bits(_cast_bits_to_array_expr_flattened_1[1], 0, 0) + connect _cast_bits_to_bundle_expr_8.tag, _cast_bits_to_bundle_expr_flattened_8.tag + connect _cast_bits_to_bundle_expr_flattened_8.body, bits(_cast_bits_to_array_expr_flattened_1[1], 1, 1) + connect _cast_bits_to_bundle_expr_8.body, _cast_bits_to_bundle_expr_flattened_8.body + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_bundle_expr_8 + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_14, __enum_structural_eq_15) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_16, __enum_structural_eq_17) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_9: Ty2 + wire _cast_bits_to_bundle_expr_flattened_9: Ty6 + connect _cast_bits_to_bundle_expr_flattened_9.`0`, bits(UInt<3>(0h2), 1, 0) + wire _cast_bits_to_bundle_expr_10: Ty1 + wire _cast_bits_to_bundle_expr_flattened_10: Ty1 + connect _cast_bits_to_bundle_expr_flattened_10.tag, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 0, 0) + connect _cast_bits_to_bundle_expr_10.tag, _cast_bits_to_bundle_expr_flattened_10.tag + connect _cast_bits_to_bundle_expr_flattened_10.body, bits(_cast_bits_to_bundle_expr_flattened_9.`0`, 1, 1) + connect _cast_bits_to_bundle_expr_10.body, _cast_bits_to_bundle_expr_flattened_10.body + connect _cast_bits_to_bundle_expr_9.`0`, _cast_bits_to_bundle_expr_10 + connect _cast_bits_to_bundle_expr_flattened_9.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_9.`1`, _cast_bits_to_bundle_expr_flattened_9.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_9 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_18, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_19, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_9.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_16: UInt<1> + connect _bundle_structural_eq_16, and(eq(extern_child.io.opt_unit.tag, _bundle_literal_expr.tag), eq(extern_child.io.opt_unit.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit, _bundle_structural_eq_16 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_17: UInt<1> + connect _bundle_structural_eq_17, and(eq(extern_child.io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(extern_child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect extern_child_out.opt_unit_flip, _bundle_structural_eq_17 @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_20 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_18: UInt<1> + connect _bundle_structural_eq_18, and(eq(extern_child.io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(extern_child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect extern_child_out.opt_bool_flip, _bundle_structural_eq_18 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_21 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_19: UInt<1> + connect _bundle_structural_eq_19, and(eq(extern_child.io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(extern_child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect extern_child_out.opt_opt_unit_flip, _bundle_structural_eq_19 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_22, __enum_structural_eq_23) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_20: UInt<1> + connect _bundle_structural_eq_20, and(eq(extern_child.io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(extern_child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_21: UInt<1> + connect _bundle_structural_eq_21, and(eq(extern_child.io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(extern_child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect extern_child_out.array_opt_bool_flip, and(_bundle_structural_eq_20, _bundle_structural_eq_21) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_24, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_22: UInt<1> + connect _bundle_structural_eq_22, and(eq(extern_child.io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(extern_child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect extern_child_out.struct_opt_bool_flip, and(_bundle_structural_eq_22, eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _bundle_literal_expr @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_23: UInt<1> + connect _bundle_structural_eq_23, and(eq(child.io.opt_unit.tag, _bundle_literal_expr.tag), eq(child.io.opt_unit.body, _bundle_literal_expr.body)) + connect child_out.opt_unit, _bundle_structural_eq_23 @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq_24: UInt<1> + connect _bundle_structural_eq_24, and(eq(child.io.opt_unit_flip.tag, _bundle_literal_expr.tag), eq(child.io.opt_unit_flip.body, _bundle_literal_expr.body)) + connect child_out.opt_unit_flip, _bundle_structural_eq_24 @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _bundle_literal_expr_2 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_25: UInt<1> + connect _bundle_structural_eq_25, and(eq(child.io.opt_bool.tag, _bundle_literal_expr_2.tag), eq(child.io.opt_bool.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool, _bundle_structural_eq_25 @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_structural_eq_26: UInt<1> + connect _bundle_structural_eq_26, and(eq(child.io.opt_bool_flip.tag, _bundle_literal_expr_2.tag), eq(child.io.opt_bool_flip.body, _bundle_literal_expr_2.body)) + connect child_out.opt_bool_flip, _bundle_structural_eq_26 @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_27: UInt<1> + connect _bundle_structural_eq_27, and(eq(child.io.opt_opt_unit.tag, _bundle_literal_expr_3.tag), eq(child.io.opt_opt_unit.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit, _bundle_structural_eq_27 @[module-XXXXXXXXXX.rs 15:1] + wire _bundle_structural_eq_28: UInt<1> + connect _bundle_structural_eq_28, and(eq(child.io.opt_opt_unit_flip.tag, _bundle_literal_expr_3.tag), eq(child.io.opt_opt_unit_flip.body, _bundle_literal_expr_3.body)) + connect child_out.opt_opt_unit_flip, _bundle_structural_eq_28 @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_29: UInt<1> + connect _bundle_structural_eq_29, and(eq(child.io.array_opt_bool[0].tag, _array_literal_expr[0].tag), eq(child.io.array_opt_bool[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_30: UInt<1> + connect _bundle_structural_eq_30, and(eq(child.io.array_opt_bool[1].tag, _array_literal_expr[1].tag), eq(child.io.array_opt_bool[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool, and(_bundle_structural_eq_29, _bundle_structural_eq_30) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_structural_eq_31: UInt<1> + connect _bundle_structural_eq_31, and(eq(child.io.array_opt_bool_flip[0].tag, _array_literal_expr[0].tag), eq(child.io.array_opt_bool_flip[0].body, _array_literal_expr[0].body)) + wire _bundle_structural_eq_32: UInt<1> + connect _bundle_structural_eq_32, and(eq(child.io.array_opt_bool_flip[1].tag, _array_literal_expr[1].tag), eq(child.io.array_opt_bool_flip[1].body, _array_literal_expr[1].body)) + connect child_out.array_opt_bool_flip, and(_bundle_structural_eq_31, _bundle_structural_eq_32) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_33: UInt<1> + connect _bundle_structural_eq_33, and(eq(child.io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(child.io.struct_opt_bool.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool, and(_bundle_structural_eq_33, eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + wire _bundle_structural_eq_34: UInt<1> + connect _bundle_structural_eq_34, and(eq(child.io.struct_opt_bool_flip.`0`.tag, _bundle_literal_expr_5.`0`.tag), eq(child.io.struct_opt_bool_flip.`0`.body, _bundle_literal_expr_5.`0`.body)) + connect child_out.struct_opt_bool_flip, and(_bundle_structural_eq_34, eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_bool.tag, _bundle_literal_expr_2.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq, eq(bits(io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_opt_unit.tag, _bundle_literal_expr_3.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_11: Ty0 + wire _cast_bits_to_bundle_expr_flattened_11: Ty0 + connect _cast_bits_to_bundle_expr_flattened_11.tag, bits(bits(io.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_11.tag, _cast_bits_to_bundle_expr_flattened_11.tag + connect _cast_bits_to_bundle_expr_flattened_11.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_11.body, _cast_bits_to_bundle_expr_flattened_11.body + wire _cast_bits_to_bundle_expr_12: Ty0 + wire _cast_bits_to_bundle_expr_flattened_12: Ty0 + connect _cast_bits_to_bundle_expr_flattened_12.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_12.tag, _cast_bits_to_bundle_expr_flattened_12.tag + connect _cast_bits_to_bundle_expr_flattened_12.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_12.body, _cast_bits_to_bundle_expr_flattened_12.body + when eq(_cast_bits_to_bundle_expr_11.tag, _cast_bits_to_bundle_expr_12.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_11.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_13: Ty5 + invalidate _cast_bits_to_bundle_expr_13 + wire _cast_bits_to_bundle_expr_14: Ty5 + invalidate _cast_bits_to_bundle_expr_14 + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[0].tag, _array_literal_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_2, eq(bits(io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[1].tag, _array_literal_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_3, eq(bits(io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_4, eq(bits(io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_bool.tag, _cast_bits_to_bundle_expr_1.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_5, eq(bits(io_zeros.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_1.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_opt_unit.tag, _cast_bits_to_bundle_expr_1.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, __enum_structural_eq_26 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_15: Ty0 + wire _cast_bits_to_bundle_expr_flattened_13: Ty0 + connect _cast_bits_to_bundle_expr_flattened_13.tag, bits(bits(io_zeros.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_15.tag, _cast_bits_to_bundle_expr_flattened_13.tag + connect _cast_bits_to_bundle_expr_flattened_13.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_15.body, _cast_bits_to_bundle_expr_flattened_13.body + wire _cast_bits_to_bundle_expr_16: Ty0 + wire _cast_bits_to_bundle_expr_flattened_14: Ty0 + connect _cast_bits_to_bundle_expr_flattened_14.tag, bits(bits(_cast_bits_to_bundle_expr_1.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_16.tag, _cast_bits_to_bundle_expr_flattened_14.tag + connect _cast_bits_to_bundle_expr_flattened_14.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_16.body, _cast_bits_to_bundle_expr_flattened_14.body + when eq(_cast_bits_to_bundle_expr_15.tag, _cast_bits_to_bundle_expr_16.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_15.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_17: Ty5 + invalidate _cast_bits_to_bundle_expr_17 + wire _cast_bits_to_bundle_expr_18: Ty5 + invalidate _cast_bits_to_bundle_expr_18 + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[0].tag, _cast_bits_to_array_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_7, eq(bits(io_zeros.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[1].tag, _cast_bits_to_array_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_8, eq(bits(io_zeros.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.struct_opt_bool.`0`.tag, _cast_bits_to_bundle_expr_4.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_zeros.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_9, eq(bits(io_zeros.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_4.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_10, eq(bits(io_alternating.opt_bool.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool_flip.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_bool_flip.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_11, eq(bits(io_alternating.opt_bool_flip.body, 0, 0), bits(_cast_bits_to_bundle_expr_6.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, __enum_structural_eq_27 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_19: Ty0 + wire _cast_bits_to_bundle_expr_flattened_15: Ty0 + connect _cast_bits_to_bundle_expr_flattened_15.tag, bits(bits(io_alternating.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_19.tag, _cast_bits_to_bundle_expr_flattened_15.tag + connect _cast_bits_to_bundle_expr_flattened_15.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_19.body, _cast_bits_to_bundle_expr_flattened_15.body + wire _cast_bits_to_bundle_expr_20: Ty0 + wire _cast_bits_to_bundle_expr_flattened_16: Ty0 + connect _cast_bits_to_bundle_expr_flattened_16.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_20.tag, _cast_bits_to_bundle_expr_flattened_16.tag + connect _cast_bits_to_bundle_expr_flattened_16.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_20.body, _cast_bits_to_bundle_expr_flattened_16.body + when eq(_cast_bits_to_bundle_expr_19.tag, _cast_bits_to_bundle_expr_20.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_19.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_21: Ty5 + invalidate _cast_bits_to_bundle_expr_21 + wire _cast_bits_to_bundle_expr_22: Ty5 + invalidate _cast_bits_to_bundle_expr_22 + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit_flip.tag, _cast_bits_to_bundle_expr_6.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.opt_opt_unit_flip.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, __enum_structural_eq_28 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_23: Ty0 + wire _cast_bits_to_bundle_expr_flattened_17: Ty0 + connect _cast_bits_to_bundle_expr_flattened_17.tag, bits(bits(io_alternating.opt_opt_unit_flip.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_23.tag, _cast_bits_to_bundle_expr_flattened_17.tag + connect _cast_bits_to_bundle_expr_flattened_17.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_23.body, _cast_bits_to_bundle_expr_flattened_17.body + wire _cast_bits_to_bundle_expr_24: Ty0 + wire _cast_bits_to_bundle_expr_flattened_18: Ty0 + connect _cast_bits_to_bundle_expr_flattened_18.tag, bits(bits(_cast_bits_to_bundle_expr_6.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_24.tag, _cast_bits_to_bundle_expr_flattened_18.tag + connect _cast_bits_to_bundle_expr_flattened_18.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_24.body, _cast_bits_to_bundle_expr_flattened_18.body + when eq(_cast_bits_to_bundle_expr_23.tag, _cast_bits_to_bundle_expr_24.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_23.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_25: Ty5 + invalidate _cast_bits_to_bundle_expr_25 + wire _cast_bits_to_bundle_expr_26: Ty5 + invalidate _cast_bits_to_bundle_expr_26 + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[0].tag, _cast_bits_to_array_expr_1[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_14, eq(bits(io_alternating.array_opt_bool[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[1].tag, _cast_bits_to_array_expr_1[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_15, eq(bits(io_alternating.array_opt_bool[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[0].tag, _cast_bits_to_array_expr_1[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_16, eq(bits(io_alternating.array_opt_bool_flip[0].body, 0, 0), bits(_cast_bits_to_array_expr_1[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[1].tag, _cast_bits_to_array_expr_1[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.array_opt_bool_flip[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_17, eq(bits(io_alternating.array_opt_bool_flip[1].body, 0, 0), bits(_cast_bits_to_array_expr_1[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool.`0`.tag, _cast_bits_to_bundle_expr_9.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_18, eq(bits(io_alternating.struct_opt_bool.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool_flip.`0`.tag, _cast_bits_to_bundle_expr_9.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(io_alternating.struct_opt_bool_flip.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_19, eq(bits(io_alternating.struct_opt_bool_flip.`0`.body, 0, 0), bits(_cast_bits_to_bundle_expr_9.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_bool.tag, _bundle_literal_expr_2.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_bool.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_20, eq(bits(extern_child.io.opt_bool.body, 0, 0), bits(_bundle_literal_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_opt_unit.tag, _bundle_literal_expr_3.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.opt_opt_unit.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_bits_to_bundle_expr_27: Ty0 + wire _cast_bits_to_bundle_expr_flattened_19: Ty0 + connect _cast_bits_to_bundle_expr_flattened_19.tag, bits(bits(extern_child.io.opt_opt_unit.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_27.tag, _cast_bits_to_bundle_expr_flattened_19.tag + connect _cast_bits_to_bundle_expr_flattened_19.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_27.body, _cast_bits_to_bundle_expr_flattened_19.body + wire _cast_bits_to_bundle_expr_28: Ty0 + wire _cast_bits_to_bundle_expr_flattened_20: Ty0 + connect _cast_bits_to_bundle_expr_flattened_20.tag, bits(bits(_bundle_literal_expr_3.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_28.tag, _cast_bits_to_bundle_expr_flattened_20.tag + connect _cast_bits_to_bundle_expr_flattened_20.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_28.body, _cast_bits_to_bundle_expr_flattened_20.body + when eq(_cast_bits_to_bundle_expr_27.tag, _cast_bits_to_bundle_expr_28.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(_cast_bits_to_bundle_expr_27.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_29: Ty5 + invalidate _cast_bits_to_bundle_expr_29 + wire _cast_bits_to_bundle_expr_30: Ty5 + invalidate _cast_bits_to_bundle_expr_30 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[0].tag, _array_literal_expr[0].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[0].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_22, eq(bits(extern_child.io.array_opt_bool[0].body, 0, 0), bits(_array_literal_expr[0].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[1].tag, _array_literal_expr[1].tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.array_opt_bool[1].tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_23, eq(bits(extern_child.io.array_opt_bool[1].body, 0, 0), bits(_array_literal_expr[1].body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.struct_opt_bool.`0`.tag, _bundle_literal_expr_5.`0`.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(extern_child.io.struct_opt_bool.`0`.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_24, eq(bits(extern_child.io.struct_opt_bool.`0`.body, 0, 0), bits(_bundle_literal_expr_5.`0`.body, 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty3 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty3 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; + let m_uints = simplify_enums(m, SimplifyEnumsKind::ReplaceWithUInt).unwrap(); + dbg!(m_uints); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m_uints => + options: ExportOptions { + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/check_deduce_structural_eq_flags_parent.fir": r"FIRRTL version 3.2.0 +circuit check_deduce_structural_eq_flags_parent: + type Ty0 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty1 = {flip opt_unit_flip: UInt<1>, opt_unit: UInt<1>, flip opt_bool_flip: UInt<2>, opt_bool: UInt<2>, flip opt_opt_unit_flip: UInt<2>, opt_opt_unit: UInt<2>, flip array_opt_bool_flip: UInt<2>[2], array_opt_bool: UInt<2>[2], flip struct_opt_bool_flip: Ty0, struct_opt_bool: Ty0} + type Ty2 = {opt_unit_flip: UInt<1>, opt_unit: UInt<1>, opt_bool_flip: UInt<1>, opt_bool: UInt<1>, opt_opt_unit_flip: UInt<1>, opt_opt_unit: UInt<1>, array_opt_bool_flip: UInt<1>, array_opt_bool: UInt<1>, struct_opt_bool_flip: UInt<1>, struct_opt_bool: UInt<1>} + type Ty3 = {tag: UInt<1>, body: UInt<0>} + type Ty4 = {} + type Ty5 = {tag: UInt<1>, body: UInt<1>} + type Ty6 = {`0`: UInt<2>, `1`: UInt<1>} + type Ty7 = {io: Ty1} + module check_deduce_structural_eq_flags_parent: @[module-XXXXXXXXXX.rs 1:1] + input io: Ty1 @[module-XXXXXXXXXX.rs 2:1] + input io_zeros: Ty1 @[module-XXXXXXXXXX.rs 3:1] + input io_alternating: Ty1 @[module-XXXXXXXXXX.rs 4:1] + output parent_out: Ty2 @[module-XXXXXXXXXX.rs 5:1] + output parent_zeros_out: Ty2 @[module-XXXXXXXXXX.rs 6:1] + output parent_alternating_out: Ty2 @[module-XXXXXXXXXX.rs 7:1] + output extern_child_out: Ty2 @[module-XXXXXXXXXX.rs 8:1] + output child_out: Ty2 @[module-XXXXXXXXXX.rs 9:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_1: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_2: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_3: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_4: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_5: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_6: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_7: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_8: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_9: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_10: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_11: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_12: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_13: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_14: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_15: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_16: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_17: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_18: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_19: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_20: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_21: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_22: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_23: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + wire __enum_structural_eq_24: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + inst extern_child of check_deduce_structural_eq_flags_extern_child @[module-XXXXXXXXXX.rs 10:1] + inst child of check_deduce_structural_eq_flags_child @[module-XXXXXXXXXX.rs 11:1] + wire _bundle_literal_expr: Ty3 + connect _bundle_literal_expr.tag, UInt<1>(0h1) + wire _bundle_literal_expr_1: Ty4 + invalidate _bundle_literal_expr_1 + connect _bundle_literal_expr.body, UInt<0>(0) + wire _cast_bundle_to_bits_expr: Ty3 + connect _cast_bundle_to_bits_expr.tag, _bundle_literal_expr.tag + connect _cast_bundle_to_bits_expr.body, _bundle_literal_expr.body + wire _cast_to_bits_expr: UInt<1> + connect _cast_to_bits_expr, cat(_cast_bundle_to_bits_expr.body, _cast_bundle_to_bits_expr.tag) + connect io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit, eq(io.opt_unit, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect parent_out.opt_unit_flip, eq(io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_literal_expr_2: Ty5 + connect _bundle_literal_expr_2.tag, UInt<1>(0h1) + connect _bundle_literal_expr_2.body, UInt<1>(0h1) + wire _cast_bundle_to_bits_expr_1: Ty5 + connect _cast_bundle_to_bits_expr_1.tag, _bundle_literal_expr_2.tag + connect _cast_bundle_to_bits_expr_1.body, _bundle_literal_expr_2.body + wire _cast_to_bits_expr_1: UInt<2> + connect _cast_to_bits_expr_1, cat(_cast_bundle_to_bits_expr_1.body, _cast_bundle_to_bits_expr_1.tag) + connect io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool, __enum_structural_eq @[module-XXXXXXXXXX.rs 14:1] + connect parent_out.opt_bool_flip, eq(io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + wire _bundle_literal_expr_3: Ty5 + connect _bundle_literal_expr_3.tag, UInt<1>(0h1) + connect _bundle_literal_expr_3.body, _cast_to_bits_expr + wire _cast_bundle_to_bits_expr_2: Ty5 + connect _cast_bundle_to_bits_expr_2.tag, _bundle_literal_expr_3.tag + connect _cast_bundle_to_bits_expr_2.body, _bundle_literal_expr_3.body + wire _cast_to_bits_expr_2: UInt<2> + connect _cast_to_bits_expr_2, cat(_cast_bundle_to_bits_expr_2.body, _cast_bundle_to_bits_expr_2.tag) + connect io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit, __enum_structural_eq_1 @[module-XXXXXXXXXX.rs 15:1] + connect parent_out.opt_opt_unit_flip, eq(io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + wire _array_literal_expr: UInt<2>[2] + wire _bundle_literal_expr_4: Ty5 + connect _bundle_literal_expr_4.tag, UInt<1>(0h1) + connect _bundle_literal_expr_4.body, UInt<1>(0h0) + wire _cast_bundle_to_bits_expr_3: Ty5 + connect _cast_bundle_to_bits_expr_3.tag, _bundle_literal_expr_4.tag + connect _cast_bundle_to_bits_expr_3.body, _bundle_literal_expr_4.body + wire _cast_to_bits_expr_3: UInt<2> + connect _cast_to_bits_expr_3, cat(_cast_bundle_to_bits_expr_3.body, _cast_bundle_to_bits_expr_3.tag) + connect _array_literal_expr[0], _cast_to_bits_expr_3 + connect _array_literal_expr[1], _cast_to_bits_expr_1 + connect io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool, and(__enum_structural_eq_2, __enum_structural_eq_3) @[module-XXXXXXXXXX.rs 16:1] + connect parent_out.array_opt_bool_flip, and(eq(io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + wire _bundle_literal_expr_5: Ty0 + connect _bundle_literal_expr_5.`0`, _cast_to_bits_expr_1 + connect _bundle_literal_expr_5.`1`, UInt<1>(0h1) + connect io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool, and(__enum_structural_eq_4, eq(io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_out.struct_opt_bool_flip, and(eq(io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_zeros.opt_unit_flip, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit, eq(io_zeros.opt_unit, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect parent_zeros_out.opt_unit_flip, eq(io_zeros.opt_unit_flip, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect io_zeros.opt_bool_flip, UInt<2>(0h0) @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool, __enum_structural_eq_5 @[module-XXXXXXXXXX.rs 14:1] + connect parent_zeros_out.opt_bool_flip, eq(io_zeros.opt_bool_flip, UInt<2>(0h0)) @[module-XXXXXXXXXX.rs 14:1] + connect io_zeros.opt_opt_unit_flip, UInt<2>(0h0) @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit, __enum_structural_eq_6 @[module-XXXXXXXXXX.rs 15:1] + connect parent_zeros_out.opt_opt_unit_flip, eq(io_zeros.opt_opt_unit_flip, UInt<2>(0h0)) @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr: UInt<2>[2] + wire _cast_bits_to_array_expr_flattened: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened[0], bits(UInt<4>(0h0), 1, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(UInt<4>(0h0), 3, 2) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect io_zeros.array_opt_bool_flip, _cast_bits_to_array_expr @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool, and(__enum_structural_eq_7, __enum_structural_eq_8) @[module-XXXXXXXXXX.rs 16:1] + connect parent_zeros_out.array_opt_bool_flip, and(eq(io_zeros.array_opt_bool_flip[0], _cast_bits_to_array_expr[0]), eq(io_zeros.array_opt_bool_flip[1], _cast_bits_to_array_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr: Ty0 + wire _cast_bits_to_bundle_expr_flattened: Ty6 + connect _cast_bits_to_bundle_expr_flattened.`0`, bits(UInt<3>(0h0), 1, 0) + connect _cast_bits_to_bundle_expr.`0`, _cast_bits_to_bundle_expr_flattened.`0` + connect _cast_bits_to_bundle_expr_flattened.`1`, bits(UInt<3>(0h0), 2, 2) + connect _cast_bits_to_bundle_expr.`1`, _cast_bits_to_bundle_expr_flattened.`1` + connect io_zeros.struct_opt_bool_flip, _cast_bits_to_bundle_expr @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool, and(__enum_structural_eq_9, eq(io_zeros.struct_opt_bool.`1`, _cast_bits_to_bundle_expr.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_zeros_out.struct_opt_bool_flip, and(eq(io_zeros.struct_opt_bool_flip.`0`, _cast_bits_to_bundle_expr.`0`), eq(io_zeros.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect io_alternating.opt_unit_flip, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit, eq(io_alternating.opt_unit, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect parent_alternating_out.opt_unit_flip, eq(io_alternating.opt_unit_flip, UInt<1>(0h0)) @[module-XXXXXXXXXX.rs 13:1] + connect io_alternating.opt_bool_flip, UInt<2>(0h2) @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool, __enum_structural_eq_10 @[module-XXXXXXXXXX.rs 14:1] + connect parent_alternating_out.opt_bool_flip, __enum_structural_eq_11 @[module-XXXXXXXXXX.rs 14:1] + connect io_alternating.opt_opt_unit_flip, UInt<2>(0h2) @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit, __enum_structural_eq_12 @[module-XXXXXXXXXX.rs 15:1] + connect parent_alternating_out.opt_opt_unit_flip, __enum_structural_eq_13 @[module-XXXXXXXXXX.rs 15:1] + wire _cast_bits_to_array_expr_1: UInt<2>[2] + wire _cast_bits_to_array_expr_flattened_1: UInt<2>[2] + connect _cast_bits_to_array_expr_flattened_1[0], bits(UInt<4>(0hA), 1, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(UInt<4>(0hA), 3, 2) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect io_alternating.array_opt_bool_flip, _cast_bits_to_array_expr_1 @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool, and(__enum_structural_eq_14, __enum_structural_eq_15) @[module-XXXXXXXXXX.rs 16:1] + connect parent_alternating_out.array_opt_bool_flip, and(__enum_structural_eq_16, __enum_structural_eq_17) @[module-XXXXXXXXXX.rs 16:1] + wire _cast_bits_to_bundle_expr_1: Ty0 + wire _cast_bits_to_bundle_expr_flattened_1: Ty6 + connect _cast_bits_to_bundle_expr_flattened_1.`0`, bits(UInt<3>(0h2), 1, 0) + connect _cast_bits_to_bundle_expr_1.`0`, _cast_bits_to_bundle_expr_flattened_1.`0` + connect _cast_bits_to_bundle_expr_flattened_1.`1`, bits(UInt<3>(0h2), 2, 2) + connect _cast_bits_to_bundle_expr_1.`1`, _cast_bits_to_bundle_expr_flattened_1.`1` + connect io_alternating.struct_opt_bool_flip, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool, and(__enum_structural_eq_18, eq(io_alternating.struct_opt_bool.`1`, _cast_bits_to_bundle_expr_1.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect parent_alternating_out.struct_opt_bool_flip, and(__enum_structural_eq_19, eq(io_alternating.struct_opt_bool_flip.`1`, _cast_bits_to_bundle_expr_1.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child.io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit, eq(extern_child.io.opt_unit, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child_out.opt_unit_flip, eq(extern_child.io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect extern_child.io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool, __enum_structural_eq_20 @[module-XXXXXXXXXX.rs 14:1] + connect extern_child_out.opt_bool_flip, eq(extern_child.io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect extern_child.io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit, __enum_structural_eq_21 @[module-XXXXXXXXXX.rs 15:1] + connect extern_child_out.opt_opt_unit_flip, eq(extern_child.io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect extern_child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool, and(__enum_structural_eq_22, __enum_structural_eq_23) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child_out.array_opt_bool_flip, and(eq(extern_child.io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(extern_child.io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect extern_child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool, and(__enum_structural_eq_24, eq(extern_child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect extern_child_out.struct_opt_bool_flip, and(eq(extern_child.io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(extern_child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child.io.opt_unit_flip, _cast_to_bits_expr @[module-XXXXXXXXXX.rs 13:1] + connect child_out.opt_unit, eq(child.io.opt_unit, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect child_out.opt_unit_flip, eq(child.io.opt_unit_flip, _cast_to_bits_expr) @[module-XXXXXXXXXX.rs 13:1] + connect child.io.opt_bool_flip, _cast_to_bits_expr_1 @[module-XXXXXXXXXX.rs 14:1] + connect child_out.opt_bool, eq(child.io.opt_bool, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect child_out.opt_bool_flip, eq(child.io.opt_bool_flip, _cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 14:1] + connect child.io.opt_opt_unit_flip, _cast_to_bits_expr_2 @[module-XXXXXXXXXX.rs 15:1] + connect child_out.opt_opt_unit, eq(child.io.opt_opt_unit, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect child_out.opt_opt_unit_flip, eq(child.io.opt_opt_unit_flip, _cast_to_bits_expr_2) @[module-XXXXXXXXXX.rs 15:1] + connect child.io.array_opt_bool_flip, _array_literal_expr @[module-XXXXXXXXXX.rs 16:1] + connect child_out.array_opt_bool, and(eq(child.io.array_opt_bool[0], _array_literal_expr[0]), eq(child.io.array_opt_bool[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect child_out.array_opt_bool_flip, and(eq(child.io.array_opt_bool_flip[0], _array_literal_expr[0]), eq(child.io.array_opt_bool_flip[1], _array_literal_expr[1])) @[module-XXXXXXXXXX.rs 16:1] + connect child.io.struct_opt_bool_flip, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 17:1] + connect child_out.struct_opt_bool, and(eq(child.io.struct_opt_bool.`0`, _bundle_literal_expr_5.`0`), eq(child.io.struct_opt_bool.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect child_out.struct_opt_bool_flip, and(eq(child.io.struct_opt_bool_flip.`0`, _bundle_literal_expr_5.`0`), eq(child.io.struct_opt_bool_flip.`1`, _bundle_literal_expr_5.`1`)) @[module-XXXXXXXXXX.rs 17:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_bool, 0, 0), bits(_cast_to_bits_expr_1, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq, eq(bits(bits(io.opt_bool, 1, 1), 0, 0), bits(bits(_cast_to_bits_expr_1, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_opt_unit, 0, 0), bits(_cast_to_bits_expr_2, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_25: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_1, __enum_structural_eq_25 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(_cast_to_bits_expr_2, 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_2: Ty4 + invalidate _cast_bits_to_bundle_expr_2 + wire _cast_bits_to_bundle_expr_3: Ty4 + invalidate _cast_bits_to_bundle_expr_3 + connect __enum_structural_eq_25, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[0], 0, 0), bits(_array_literal_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_2, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_2, eq(bits(bits(io.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_array_literal_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[1], 0, 0), bits(_array_literal_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_3, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_3, eq(bits(bits(io.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_array_literal_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.struct_opt_bool.`0`, 0, 0), bits(_bundle_literal_expr_5.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_4, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_4, eq(bits(bits(io.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_bundle_literal_expr_5.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_bool, 0, 0), bits(UInt<2>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_5, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_5, eq(bits(bits(io_zeros.opt_bool, 1, 1), 0, 0), bits(bits(UInt<2>(0h0), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_opt_unit, 0, 0), bits(UInt<2>(0h0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_26: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_6, __enum_structural_eq_26 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_zeros.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h0), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_zeros.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_4: Ty4 + invalidate _cast_bits_to_bundle_expr_4 + wire _cast_bits_to_bundle_expr_5: Ty4 + invalidate _cast_bits_to_bundle_expr_5 + connect __enum_structural_eq_26, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[0], 0, 0), bits(_cast_bits_to_array_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_7, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_7, eq(bits(bits(io_zeros.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[1], 0, 0), bits(_cast_bits_to_array_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_8, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_8, eq(bits(bits(io_zeros.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.struct_opt_bool.`0`, 0, 0), bits(_cast_bits_to_bundle_expr.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_zeros.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_9, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_9, eq(bits(bits(io_zeros.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_10, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_10, eq(bits(bits(io_alternating.opt_bool, 1, 1), 0, 0), bits(bits(UInt<2>(0h2), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool_flip, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_bool_flip, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_11, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_11, eq(bits(bits(io_alternating.opt_bool_flip, 1, 1), 0, 0), bits(bits(UInt<2>(0h2), 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_27: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_12, __enum_structural_eq_27 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h2), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_6: Ty4 + invalidate _cast_bits_to_bundle_expr_6 + wire _cast_bits_to_bundle_expr_7: Ty4 + invalidate _cast_bits_to_bundle_expr_7 + connect __enum_structural_eq_27, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit_flip, 0, 0), bits(UInt<2>(0h2), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.opt_opt_unit_flip, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_28: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_13, __enum_structural_eq_28 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit_flip, 1, 1), 0, 0), 0, 0), bits(bits(bits(UInt<2>(0h2), 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(io_alternating.opt_opt_unit_flip, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_8: Ty4 + invalidate _cast_bits_to_bundle_expr_8 + wire _cast_bits_to_bundle_expr_9: Ty4 + invalidate _cast_bits_to_bundle_expr_9 + connect __enum_structural_eq_28, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[0], 0, 0), bits(_cast_bits_to_array_expr_1[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_14, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_14, eq(bits(bits(io_alternating.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[1], 0, 0), bits(_cast_bits_to_array_expr_1[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_15, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_15, eq(bits(bits(io_alternating.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[0], 0, 0), bits(_cast_bits_to_array_expr_1[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_16, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_16, eq(bits(bits(io_alternating.array_opt_bool_flip[0], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[1], 0, 0), bits(_cast_bits_to_array_expr_1[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.array_opt_bool_flip[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_17, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_17, eq(bits(bits(io_alternating.array_opt_bool_flip[1], 1, 1), 0, 0), bits(bits(_cast_bits_to_array_expr_1[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool.`0`, 0, 0), bits(_cast_bits_to_bundle_expr_1.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_18, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_18, eq(bits(bits(io_alternating.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr_1.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool_flip.`0`, 0, 0), bits(_cast_bits_to_bundle_expr_1.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(io_alternating.struct_opt_bool_flip.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_19, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_19, eq(bits(bits(io_alternating.struct_opt_bool_flip.`0`, 1, 1), 0, 0), bits(bits(_cast_bits_to_bundle_expr_1.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_bool, 0, 0), bits(_cast_to_bits_expr_1, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_bool, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_20, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_20, eq(bits(bits(extern_child.io.opt_bool, 1, 1), 0, 0), bits(bits(_cast_to_bits_expr_1, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_opt_unit, 0, 0), bits(_cast_to_bits_expr_2, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.opt_opt_unit, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire __enum_structural_eq_29: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_21, __enum_structural_eq_29 @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(extern_child.io.opt_opt_unit, 1, 1), 0, 0), 0, 0), bits(bits(bits(_cast_to_bits_expr_2, 1, 1), 0, 0), 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(bits(bits(extern_child.io.opt_opt_unit, 1, 1), 0, 0), 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_bundle_expr_10: Ty4 + invalidate _cast_bits_to_bundle_expr_10 + wire _cast_bits_to_bundle_expr_11: Ty4 + invalidate _cast_bits_to_bundle_expr_11 + connect __enum_structural_eq_29, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[0], 0, 0), bits(_array_literal_expr[0], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[0], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_22, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_22, eq(bits(bits(extern_child.io.array_opt_bool[0], 1, 1), 0, 0), bits(bits(_array_literal_expr[0], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[1], 0, 0), bits(_array_literal_expr[1], 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.array_opt_bool[1], 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_23, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_23, eq(bits(bits(extern_child.io.array_opt_bool[1], 1, 1), 0, 0), bits(bits(_array_literal_expr[1], 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.struct_opt_bool.`0`, 0, 0), bits(_bundle_literal_expr_5.`0`, 0, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(extern_child.io.struct_opt_bool.`0`, 0, 0), UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq_24, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else: + connect __enum_structural_eq_24, eq(bits(bits(extern_child.io.struct_opt_bool.`0`, 1, 1), 0, 0), bits(bits(_bundle_literal_expr_5.`0`, 1, 1), 0, 0)) @[module-XXXXXXXXXX.rs 1:1] + extmodule check_deduce_structural_eq_flags_extern_child: @[module-XXXXXXXXXX-2.rs 1:1] + output io: Ty1 @[module-XXXXXXXXXX-2.rs 2:1] + defname = check_deduce_structural_eq_flags_extern_child + module check_deduce_structural_eq_flags_child: @[module-XXXXXXXXXX-3.rs 1:1] + output io: Ty1 @[module-XXXXXXXXXX-3.rs 2:1] + connect io.opt_unit, io.opt_unit_flip @[module-XXXXXXXXXX-3.rs 4:1] + connect io.opt_bool, io.opt_bool_flip @[module-XXXXXXXXXX-3.rs 5:1] + connect io.opt_opt_unit, io.opt_opt_unit_flip @[module-XXXXXXXXXX-3.rs 6:1] + connect io.array_opt_bool, io.array_opt_bool_flip @[module-XXXXXXXXXX-3.rs 7:1] + connect io.struct_opt_bool, io.struct_opt_bool_flip @[module-XXXXXXXXXX-3.rs 8:1] +", + }; +} diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index aa028f4..7d12810 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -709,44 +709,35 @@ circuit check_enum_cmp_eq: input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - match lhs: @[module-XXXXXXXXXX.rs 5:1] + wire _cast_enum_to_bits_expr: UInt<10> + match lhs: A: - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - B(_match_arm_value): - skip - C(_match_arm_value_1): - skip - B(_match_arm_value_2): - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B(_match_arm_value_3): - connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1] - C(_match_arm_value_4): - skip - C(_match_arm_value_5): - match rhs: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B(_match_arm_value_6): - skip - C(_match_arm_value_7): - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0]) - connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1]) - connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + connect _cast_enum_to_bits_expr, UInt<10>(0) + B(_cast_enum_to_bits_expr_B): + connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10) + C(_cast_enum_to_bits_expr_C): + wire _cast_array_to_bits_expr: UInt<1>[3] + connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0] + connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1] + connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2] + wire _cast_to_bits_expr: UInt<3> + connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) + connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10) + wire _cast_enum_to_bits_expr_1: UInt<10> + match rhs: + A: + connect _cast_enum_to_bits_expr_1, UInt<10>(0) + B(_cast_enum_to_bits_expr_B_1): + connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10) + C(_cast_enum_to_bits_expr_C_1): + wire _cast_array_to_bits_expr_1: UInt<1>[3] + connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0] + connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1] + connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2] + wire _cast_to_bits_expr_1: UInt<3> + connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0])) + connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10) + connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -764,60 +755,53 @@ circuit check_enum_cmp_eq: input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - match lhs.tag: @[module-XXXXXXXXXX.rs 5:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + wire _cast_enum_to_bits_expr: UInt<2> + match lhs.tag: A: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - B: - skip - C: - skip + connect _cast_enum_to_bits_expr, UInt<2>(0) B: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B: - connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - C: - skip + connect _cast_enum_to_bits_expr, UInt<2>(1) C: - match rhs.tag: @[module-XXXXXXXXXX.rs 5:1] - A: - skip - B: - skip - C: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + connect _cast_enum_to_bits_expr, UInt<2>(2) + wire _cast_enum_to_bits_expr_1: UInt<2> + match rhs.tag: + A: + connect _cast_enum_to_bits_expr_1, UInt<2>(0) + B: + connect _cast_enum_to_bits_expr_1, UInt<2>(1) + C: + connect _cast_enum_to_bits_expr_1, UInt<2>(2) + when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1] + match lhs.tag: @[module-XXXXXXXXXX.rs 1:1] + A: + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + B: + connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + C: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -834,51 +818,36 @@ circuit check_enum_cmp_eq: input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1] + when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 @@ -894,51 +863,36 @@ circuit check_enum_cmp_eq: input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1] input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1] output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1] - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1] - else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1] - skip - else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1] - skip - else: - wire _array_literal_expr: UInt<1>[3] - wire _cast_bits_to_array_expr: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] - connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] - connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] - wire _cast_bits_to_array_expr_1: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] - connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] - connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] - connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1] + wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1] + connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1] + connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1] + when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1] + else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1] + connect __enum_structural_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 1:1] + else: + wire _cast_bits_to_array_expr: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) + connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0] + connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) + connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1] + connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) + connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2] + wire _cast_bits_to_array_expr_1: UInt<1>[3] + wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3] + connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) + connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0] + connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) + connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1] + connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) + connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] + wire _array_structural_eq: UInt<1> + connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])) + wire _array_structural_eq_1: UInt<1> + connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])) + connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1] ", }; } @@ -4909,34 +4863,20 @@ circuit check_struct_cmp_eq: input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1] output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1] output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1] - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`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 tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - wire _array_literal_expr_1: UInt<1>[3] - connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`) - wire _cast_array_to_bits_expr_1: UInt<1>[3] - connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0] - connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1] - connect _cast_array_to_bits_expr_1[2], _array_literal_expr_1[2] - wire _cast_to_bits_expr_1: UInt<3> - connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0])) - connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1] - connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1] - connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1] + wire _bundle_structural_eq: UInt<1> + connect _bundle_structural_eq, and(eq(tuple_lhs.`0`, tuple_rhs.`0`), eq(tuple_lhs.`1`, tuple_rhs.`1`)) + wire _bundle_structural_eq_1: UInt<1> + connect _bundle_structural_eq_1, and(_bundle_structural_eq, eq(tuple_lhs.`2`, tuple_rhs.`2`)) + connect tuple_cmp_eq, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 5:1] + connect tuple_cmp_ne, not(_bundle_structural_eq_1) @[module-XXXXXXXXXX.rs 7:1] + wire _bundle_structural_eq_2: UInt<1> + connect _bundle_structural_eq_2, 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_2 @[module-XXXXXXXXXX.rs 11:1] + connect test_struct_cmp_ne, not(_bundle_structural_eq_2) @[module-XXXXXXXXXX.rs 13:1] connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1] - connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1] + connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19:1] connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1] - connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1] + connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1] ", }; } diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 223c4bc..343b87b 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -3749,3 +3749,67 @@ at module-XXXXXXXXXX.rs:12:1: in InstantiatedModule(formal_counter: formal_count } } } + +#[hdl_module(outline_generated)] +pub fn enum_structural_eq() { + #[hdl] + let a: HdlOption> = m.input(); + #[hdl] + let b: HdlOption> = m.input(); + #[hdl] + let eq: Bool = m.output(); + #[hdl] + let structural_eq: Bool = m.output(); + #[hdl] + let bit_eq: Bool = m.output(); + + connect(eq, a.cmp_eq(b)); + // explicitly use StructuralEq (though cmp_eq also uses it above) + connect( + structural_eq, + fayalite::expr::ops::StructuralEq::new(Expr::canonical(a), Expr::canonical(b)), + ); + connect(bit_eq, a.cast_to_bits().cmp_eq(b.cast_to_bits())); +} + +#[test] +fn test_enum_structural_eq() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(enum_structural_eq()); + let _checked_vcd_output = + checked_vcd_output!(&mut sim, "tests/sim/expected/test_enum_structural_eq.vcd"); + for a in 0..8u8 { + for b in 0..8u8 { + dbg!(a); + dbg!(b); + let a_sim_value = a.cast_to(UInt[3]).cast_bits_to(sim.io().a.ty()); + let b_sim_value = b.cast_to(UInt[3]).cast_bits_to(sim.io().b.ty()); + dbg!(&a_sim_value); + dbg!(&b_sim_value); + sim.write(sim.io().a, a_sim_value); + sim.write(sim.io().b, b_sim_value); + let a_with_zeroed_padding = if (a & 1) != 0 { a } else { 0 }; + let b_with_zeroed_padding = if (b & 1) != 0 { b } else { 0 }; + dbg!(a_with_zeroed_padding); + dbg!(b_with_zeroed_padding); + let expected_eq = a_with_zeroed_padding == b_with_zeroed_padding; + let expected_structural_eq = a_with_zeroed_padding == b_with_zeroed_padding; + let expected_bit_eq = a == b; + dbg!(expected_eq); + dbg!(expected_structural_eq); + dbg!(expected_bit_eq); + sim.advance_time(SimDuration::from_micros(1)); + assert_eq!(sim.read_bool(sim.io().eq), expected_eq); + assert_eq!( + sim.read_bool(sim.io().structural_eq), + expected_structural_eq + ); + assert_eq!(sim.read_bool(sim.io().bit_eq), expected_bit_eq); + } + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/test_enum_structural_eq.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt new file mode 100644 index 0000000..bad046e --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.txt @@ -0,0 +1,522 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "", + ty: Enum { + HdlNone, + HdlSome, + }, + }, + SlotDebugData { + name: "", + ty: Enum { + HdlNone, + HdlSome, + }, + }, + ], + .. + }, + big_slots: StatePartLayout { + len: 13, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + SlotDebugData { + name: "", + ty: UInt<3>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + SlotDebugData { + name: "", + ty: UInt<3>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(10), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x1, + }, + 1: Const { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x0, + }, + 2: Copy { + dest: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + src: StatePartIndex(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} }, + }, + 3: SliceInt { + dest: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + start: 1, + len: 2, + }, + // at: module-XXXXXXXXXX.rs:3:1 + 4: AndBigWithSmallImmediate { + dest: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + lhs: StatePartIndex(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} }, + rhs: 0x1, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 5: Copy { + dest: StatePartIndex(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + src: StatePartIndex(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} }, + }, + 6: SliceInt { + dest: StatePartIndex(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + start: 1, + len: 2, + }, + 7: CmpEq { + dest: StatePartIndex(11), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + }, + 8: CmpEq { + dest: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + rhs: StatePartIndex(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 9: Copy { + dest: StatePartIndex(8), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", ty: Bool }, + src: StatePartIndex(12), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:2:1 + 10: AndBigWithSmallImmediate { + dest: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + lhs: StatePartIndex(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} }, + rhs: 0x1, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 11: BranchIfSmallNeImmediate { + target: 14, + lhs: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x0, + }, + 12: BranchIfSmallNeImmediate { + target: 14, + lhs: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x0, + }, + 13: Copy { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(10), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + 14: BranchIfSmallNeImmediate { + target: 17, + lhs: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x1, + }, + 15: BranchIfSmallNeImmediate { + target: 17, + lhs: StatePartIndex(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, + rhs: 0x1, + }, + 16: Copy { + dest: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(11), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 17: Copy { + dest: StatePartIndex(6), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", ty: Bool }, + src: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 18: Copy { + dest: StatePartIndex(7), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", ty: Bool }, + src: StatePartIndex(9), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 19: Return, + ], + .. + }, + pc: 19, + memory_write_log: [], + assert_failed_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [ + 1, + 1, + ], + }, + big_slots: StatePart { + value: [ + 7, + 7, + 3, + 7, + 7, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + ], + }, + sim_only_slots: StatePart { + value: [], + }, + }, + io: Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }, + global_io: {}, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.a, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.b, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.structural_eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.bit_eq, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.a, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.b, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.bit_eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.eq, + Instance { + name: ::enum_structural_eq, + instantiated: Module { + name: enum_structural_eq, + .. + }, + }.structural_eq, + }, + did_initial_settle: true, + clocks_for_past: {}, + }, + extern_modules: [], + trace_decls: TraceModule { + name: "enum_structural_eq", + children: [ + TraceModuleIO { + name: "a", + child: TraceEnumWithFields { + name: "a", + discriminant: TraceEnumDiscriminant { + location: TraceScalarId(0), + name: "$tag", + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + non_empty_fields: [ + TraceUInt { + location: TraceScalarId(1), + name: "HdlSome", + ty: UInt<2>, + flow: Source, + }, + ], + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + TraceModuleIO { + name: "b", + child: TraceEnumWithFields { + name: "b", + discriminant: TraceEnumDiscriminant { + location: TraceScalarId(2), + name: "$tag", + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + non_empty_fields: [ + TraceUInt { + location: TraceScalarId(3), + name: "HdlSome", + ty: UInt<2>, + flow: Source, + }, + ], + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + flow: Source, + }, + TraceModuleIO { + name: "eq", + child: TraceBool { + location: TraceScalarId(4), + name: "eq", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + TraceModuleIO { + name: "structural_eq", + child: TraceBool { + location: TraceScalarId(5), + name: "structural_eq", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + TraceModuleIO { + name: "bit_eq", + child: TraceBool { + location: TraceScalarId(6), + name: "bit_eq", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: EnumDiscriminant { + index: StatePartIndex(0), + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x3, + last_state: 0x3, + }, + SimTrace { + id: TraceScalarId(2), + kind: EnumDiscriminant { + index: StatePartIndex(1), + ty: Enum { + HdlNone, + HdlSome(UInt<2>), + }, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(5), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x3, + last_state: 0x3, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigBool { + index: StatePartIndex(6), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigBool { + index: StatePartIndex(7), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigBool { + index: StatePartIndex(8), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + clocks_triggered: [], + event_queue: EventQueue(EventQueueData { + instant: 64 μs, + events: {}, + }), + waiting_sensitivity_sets_by_address: {}, + waiting_sensitivity_sets_by_compiled_value: {}, + asserts: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd new file mode 100644 index 0000000..8da11c9 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/test_enum_structural_eq.vcd @@ -0,0 +1,282 @@ +$timescale 1 ps $end +$scope module enum_structural_eq $end +$scope struct a $end +$var string 1 +LxwI \$tag $end +$var wire 2 {bf!u HdlSome $end +$upscope $end +$scope struct b $end +$var string 1 O%@#" \$tag $end +$var wire 2 ]xpB, HdlSome $end +$upscope $end +$var wire 1 Yp4xI eq $end +$var wire 1 >R/<6 structural_eq $end +$var wire 1 ,}=e] bit_eq $end +$upscope $end +$enddefinitions $end +$dumpvars +sHdlNone\x20(0) +LxwI +b0 {bf!u +sHdlNone\x20(0) O%@#" +b0 ]xpB, +1Yp4xI +1>R/<6 +1,}=e] +$end +#1000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +0,}=e] +#2000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +1Yp4xI +1>R/<6 +#3000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#4000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +1Yp4xI +1>R/<6 +#5000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#6000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +1Yp4xI +1>R/<6 +#7000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#8000000 +sHdlSome\x20(1) +LxwI +sHdlNone\x20(0) O%@#" +b0 ]xpB, +#9000000 +sHdlSome\x20(1) O%@#" +1Yp4xI +1>R/<6 +1,}=e] +#10000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +0Yp4xI +0>R/<6 +0,}=e] +#11000000 +sHdlSome\x20(1) O%@#" +#12000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +#13000000 +sHdlSome\x20(1) O%@#" +#14000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +#15000000 +sHdlSome\x20(1) O%@#" +#16000000 +sHdlNone\x20(0) +LxwI +b1 {bf!u +sHdlNone\x20(0) O%@#" +b0 ]xpB, +1Yp4xI +1>R/<6 +#17000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#18000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +1Yp4xI +1>R/<6 +1,}=e] +#19000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +0,}=e] +#20000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +1Yp4xI +1>R/<6 +#21000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#22000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +1Yp4xI +1>R/<6 +#23000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#24000000 +sHdlSome\x20(1) +LxwI +sHdlNone\x20(0) O%@#" +b0 ]xpB, +#25000000 +sHdlSome\x20(1) O%@#" +#26000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +#27000000 +sHdlSome\x20(1) O%@#" +1Yp4xI +1>R/<6 +1,}=e] +#28000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +0Yp4xI +0>R/<6 +0,}=e] +#29000000 +sHdlSome\x20(1) O%@#" +#30000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +#31000000 +sHdlSome\x20(1) O%@#" +#32000000 +sHdlNone\x20(0) +LxwI +b10 {bf!u +sHdlNone\x20(0) O%@#" +b0 ]xpB, +1Yp4xI +1>R/<6 +#33000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#34000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +1Yp4xI +1>R/<6 +#35000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#36000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +1Yp4xI +1>R/<6 +1,}=e] +#37000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +0,}=e] +#38000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +1Yp4xI +1>R/<6 +#39000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#40000000 +sHdlSome\x20(1) +LxwI +sHdlNone\x20(0) O%@#" +b0 ]xpB, +#41000000 +sHdlSome\x20(1) O%@#" +#42000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +#43000000 +sHdlSome\x20(1) O%@#" +#44000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +#45000000 +sHdlSome\x20(1) O%@#" +1Yp4xI +1>R/<6 +1,}=e] +#46000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +0Yp4xI +0>R/<6 +0,}=e] +#47000000 +sHdlSome\x20(1) O%@#" +#48000000 +sHdlNone\x20(0) +LxwI +b11 {bf!u +sHdlNone\x20(0) O%@#" +b0 ]xpB, +1Yp4xI +1>R/<6 +#49000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#50000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +1Yp4xI +1>R/<6 +#51000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#52000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +1Yp4xI +1>R/<6 +#53000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +#54000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +1Yp4xI +1>R/<6 +1,}=e] +#55000000 +sHdlSome\x20(1) O%@#" +0Yp4xI +0>R/<6 +0,}=e] +#56000000 +sHdlSome\x20(1) +LxwI +sHdlNone\x20(0) O%@#" +b0 ]xpB, +#57000000 +sHdlSome\x20(1) O%@#" +#58000000 +sHdlNone\x20(0) O%@#" +b1 ]xpB, +#59000000 +sHdlSome\x20(1) O%@#" +#60000000 +sHdlNone\x20(0) O%@#" +b10 ]xpB, +#61000000 +sHdlSome\x20(1) O%@#" +#62000000 +sHdlNone\x20(0) O%@#" +b11 ]xpB, +#63000000 +sHdlSome\x20(1) O%@#" +1Yp4xI +1>R/<6 +1,}=e] +#64000000 diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr index 8eff725..75bb262 100644 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr @@ -75,7 +75,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -214,7 +214,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -326,7 +326,7 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 896 | pub struct OpaqueSimValue { + 929 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index 1267aa7..5c36374 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -1055,6 +1055,15 @@ "global()": "Visible" } }, + "ops::StructuralEq": { + "data": { + "$kind": "Struct", + "$constructor": "ops::StructuralEq::with_flags", + "lhs()": "Visible", + "rhs()": "Visible", + "flags()": "Opaque" + } + }, "BlockId": { "data": { "$kind": "Opaque"