forked from libre-chip/fayalite
Compare commits
No commits in common. "cmp_eq-opts" and "master" have entirely different histories.
cmp_eq-opt
...
master
31 changed files with 253 additions and 8983 deletions
|
|
@ -1133,7 +1133,6 @@ impl ToTokens for ParsedBundle {
|
||||||
let mut fields_expr_ne = vec![];
|
let mut fields_expr_ne = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
let mut fields_valueless_ne = vec![];
|
let mut fields_valueless_ne = vec![];
|
||||||
let mut fields_structural_eq = vec![];
|
|
||||||
for field in fields.named() {
|
for field in fields.named() {
|
||||||
let field_ident = field.ident();
|
let field_ident = field.ident();
|
||||||
let field_ty = field.ty();
|
let field_ty = field.ty();
|
||||||
|
|
@ -1142,9 +1141,6 @@ impl ToTokens for ParsedBundle {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||||
});
|
});
|
||||||
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
|
|
||||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
|
||||||
});
|
|
||||||
fields_value_eq.push(quote_spanned! {span=>
|
fields_value_eq.push(quote_spanned! {span=>
|
||||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#field_ident,
|
__lhs.#field_ident,
|
||||||
|
|
@ -1192,7 +1188,6 @@ impl ToTokens for ParsedBundle {
|
||||||
let expr_ne_body;
|
let expr_ne_body;
|
||||||
let valueless_eq_body;
|
let valueless_eq_body;
|
||||||
let valueless_ne_body;
|
let valueless_ne_body;
|
||||||
let structural_eq;
|
|
||||||
if fields_len == 0 {
|
if fields_len == 0 {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
true
|
true
|
||||||
|
|
@ -1212,9 +1207,6 @@ impl ToTokens for ParsedBundle {
|
||||||
valueless_ne_body = quote_spanned! {span=>
|
valueless_ne_body = quote_spanned! {span=>
|
||||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||||
};
|
};
|
||||||
structural_eq = quote_spanned! {span=>
|
|
||||||
true
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
value_eq_body = quote_spanned! {span=>
|
value_eq_body = quote_spanned! {span=>
|
||||||
#(#fields_value_eq)&*
|
#(#fields_value_eq)&*
|
||||||
|
|
@ -1238,17 +1230,12 @@ impl ToTokens for ParsedBundle {
|
||||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||||
#(#fields_valueless_ne)|*
|
#(#fields_valueless_ne)|*
|
||||||
};
|
};
|
||||||
structural_eq = quote_spanned! {span=>
|
|
||||||
#(#fields_structural_eq)&&*
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__lhs: Self,
|
||||||
|
|
@ -1274,16 +1261,6 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
|
||||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
|
||||||
::fayalite::expr::ops::StructuralEq::try_new(
|
|
||||||
::fayalite::expr::Expr::canonical(__lhs),
|
|
||||||
::fayalite::expr::Expr::canonical(__rhs),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#expr_eq_body
|
#expr_eq_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1292,14 +1269,6 @@ impl ToTokens for ParsedBundle {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
|
||||||
return !::fayalite::expr::ToExpr::to_expr(
|
|
||||||
&::fayalite::expr::ops::StructuralEq::new(
|
|
||||||
::fayalite::expr::Expr::canonical(__lhs),
|
|
||||||
::fayalite::expr::Expr::canonical(__rhs),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#expr_ne_body
|
#expr_ne_body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,9 +643,7 @@ impl ToTokens for ParsedEnum {
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
#[allow(non_snake_case, dead_code)]
|
#[allow(non_snake_case, dead_code)]
|
||||||
#vis fn #ident(
|
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||||
#self_token,
|
|
||||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
|
||||||
::fayalite::sim::value::SimValue::from_value(
|
::fayalite::sim::value::SimValue::from_value(
|
||||||
#self_token.#sim_builder_ty_field_ident,
|
#self_token.#sim_builder_ty_field_ident,
|
||||||
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
|
||||||
|
|
@ -931,14 +929,8 @@ impl ToTokens for ParsedEnum {
|
||||||
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
fn fmt(
|
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||||
&self,
|
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
|
||||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
|
||||||
) -> ::fayalite::__std::fmt::Result {
|
|
||||||
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
|
|
||||||
self,
|
|
||||||
f,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.to_tokens(tokens);
|
}.to_tokens(tokens);
|
||||||
|
|
@ -954,7 +946,6 @@ impl ToTokens for ParsedEnum {
|
||||||
let mut variants_value_eq = vec![];
|
let mut variants_value_eq = vec![];
|
||||||
let mut variants_expr_eq = vec![];
|
let mut variants_expr_eq = vec![];
|
||||||
let mut fields_valueless_eq = vec![];
|
let mut fields_valueless_eq = vec![];
|
||||||
let mut structural_eq: Option<TokenStream> = None;
|
|
||||||
for (
|
for (
|
||||||
variant_index,
|
variant_index,
|
||||||
ParsedVariant {
|
ParsedVariant {
|
||||||
|
|
@ -980,23 +971,8 @@ impl ToTokens for ParsedEnum {
|
||||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||||
});
|
});
|
||||||
match &mut structural_eq {
|
|
||||||
Some(structural_eq) => {
|
|
||||||
structural_eq.extend(quote_spanned! {cmp_eq.span=>
|
|
||||||
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
structural_eq = Some(quote_spanned! {cmp_eq.span=>
|
|
||||||
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
variants_value_eq.push(quote_spanned! {span=>
|
variants_value_eq.push(quote_spanned! {span=>
|
||||||
(
|
(#sim_value_ident::#variant_ident(__lhs_field, _), #sim_value_ident::#variant_ident(__rhs_field, _)) => {
|
||||||
#sim_value_ident::#variant_ident(__lhs_field, _),
|
|
||||||
#sim_value_ident::#variant_ident(__rhs_field, _),
|
|
||||||
) => {
|
|
||||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||||
__lhs.#variant_ident,
|
__lhs.#variant_ident,
|
||||||
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
|
||||||
|
|
@ -1026,10 +1002,7 @@ impl ToTokens for ParsedEnum {
|
||||||
else {
|
else {
|
||||||
::fayalite::__std::unreachable!();
|
::fayalite::__std::unreachable!();
|
||||||
};
|
};
|
||||||
::fayalite::module::connect(
|
::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs));
|
||||||
__retval,
|
|
||||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fields_valueless_eq.push(quote_spanned! {span=>
|
fields_valueless_eq.push(quote_spanned! {span=>
|
||||||
|
|
@ -1070,10 +1043,7 @@ impl ToTokens for ParsedEnum {
|
||||||
}
|
}
|
||||||
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
|
||||||
variants_value_eq.push(quote_spanned! {span=>
|
variants_value_eq.push(quote_spanned! {span=>
|
||||||
(
|
(#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => {
|
||||||
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
|
|
||||||
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
|
|
||||||
) => {
|
|
||||||
__lhs_unknown == __rhs_unknown
|
__lhs_unknown == __rhs_unknown
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1090,26 +1060,17 @@ impl ToTokens for ParsedEnum {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
|
||||||
let structural_eq = structural_eq.unwrap_or_else(|| {
|
|
||||||
quote_spanned! {span=>
|
|
||||||
true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||||
#cmp_eq_where_clause
|
#cmp_eq_where_clause
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
__lhs: Self,
|
__lhs: Self,
|
||||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
|
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
|
||||||
__rhs: Self,
|
__rhs: Self,
|
||||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
|
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||||
<Self as ::fayalite::ty::Type>::SimValue>,
|
|
||||||
) -> ::fayalite::__std::primitive::bool {
|
) -> ::fayalite::__std::primitive::bool {
|
||||||
match (&*__lhs_value, &*__rhs_value) {
|
match (&*__lhs_value, &*__rhs_value) {
|
||||||
#(#variants_value_eq)*
|
#(#variants_value_eq)*
|
||||||
|
|
@ -1122,20 +1083,7 @@ impl ToTokens for ParsedEnum {
|
||||||
__lhs: ::fayalite::expr::Expr<Self>,
|
__lhs: ::fayalite::expr::Expr<Self>,
|
||||||
__rhs: ::fayalite::expr::Expr<Self>,
|
__rhs: ::fayalite::expr::Expr<Self>,
|
||||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||||
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
|
let __retval = ::fayalite::module::wire(::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name), ::fayalite::int::Bool);
|
||||||
if let ::fayalite::__std::result::Result::Ok(__retval) =
|
|
||||||
::fayalite::expr::ops::StructuralEq::try_new(
|
|
||||||
::fayalite::expr::Expr::canonical(__lhs),
|
|
||||||
::fayalite::expr::Expr::canonical(__rhs),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return ::fayalite::expr::ToExpr::to_expr(&__retval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let __retval = ::fayalite::module::wire(
|
|
||||||
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
|
|
||||||
::fayalite::int::Bool,
|
|
||||||
);
|
|
||||||
::fayalite::module::connect(__retval, false);
|
::fayalite::module::connect(__retval, false);
|
||||||
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
|
||||||
#(#variants_expr_eq)*
|
#(#variants_expr_eq)*
|
||||||
|
|
@ -1164,8 +1112,7 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimValue = #sim_value_ident #type_generics;
|
type SimValue = #sim_value_ident #type_generics;
|
||||||
type MatchVariant = #match_variant_ident #type_generics;
|
type MatchVariant = #match_variant_ident #type_generics;
|
||||||
type MatchActiveScope = ::fayalite::module::Scope;
|
type MatchActiveScope = ::fayalite::module::Scope;
|
||||||
type MatchVariantAndInactiveScope =
|
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
||||||
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
|
|
||||||
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
|
||||||
|
|
||||||
fn match_variants(
|
fn match_variants(
|
||||||
|
|
@ -1178,9 +1125,7 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::int::Bool
|
::fayalite::int::Bool
|
||||||
}
|
}
|
||||||
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
|
||||||
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
|
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
|
||||||
::fayalite::enum_::EnumType::variants(#self_token),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
@ -1189,11 +1134,7 @@ impl ToTokens for ParsedEnum {
|
||||||
::fayalite::__std::panic!("expected enum");
|
::fayalite::__std::panic!("expected enum");
|
||||||
};
|
};
|
||||||
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
|
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
|
||||||
::fayalite::__std::assert_eq!(
|
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
|
||||||
#variants_token.len(),
|
|
||||||
#variants_len,
|
|
||||||
"enum has wrong number of variants",
|
|
||||||
);
|
|
||||||
Self {
|
Self {
|
||||||
#(#from_canonical_body_fields)*
|
#(#from_canonical_body_fields)*
|
||||||
}
|
}
|
||||||
|
|
@ -1239,10 +1180,7 @@ impl ToTokens for ParsedEnum {
|
||||||
type SimBuilder = #sim_builder_ident #type_generics;
|
type SimBuilder = #sim_builder_ident #type_generics;
|
||||||
fn match_activate_scope(
|
fn match_activate_scope(
|
||||||
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
||||||
) -> (
|
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
|
||||||
<Self as ::fayalite::ty::Type>::MatchVariant,
|
|
||||||
<Self as ::fayalite::ty::Type>::MatchActiveScope,
|
|
||||||
) {
|
|
||||||
let (#variant_access_token, scope) = v.activate();
|
let (#variant_access_token, scope) = v.activate();
|
||||||
(
|
(
|
||||||
match #variant_access_token.variant_index() {
|
match #variant_access_token.variant_index() {
|
||||||
|
|
@ -1262,10 +1200,7 @@ impl ToTokens for ParsedEnum {
|
||||||
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
fn fmt(
|
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
|
||||||
&self,
|
|
||||||
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
|
||||||
) -> ::fayalite::__std::fmt::Result {
|
|
||||||
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1278,10 +1213,7 @@ impl ToTokens for ParsedEnum {
|
||||||
&self,
|
&self,
|
||||||
ty: #target #type_generics,
|
ty: #target #type_generics,
|
||||||
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
|
||||||
::fayalite::sim::value::SimValue::from_value(
|
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||||
ty,
|
|
||||||
::fayalite::__std::clone::Clone::clone(self),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn into_sim_value_with_type(
|
fn into_sim_value_with_type(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{
|
expr::{
|
||||||
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
|
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
|
||||||
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, StructuralEq},
|
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator},
|
||||||
},
|
},
|
||||||
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
|
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
|
||||||
intern::{Intern, Interned, LazyInterned},
|
intern::{Intern, Interned, LazyInterned},
|
||||||
|
|
@ -367,8 +367,6 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
|
||||||
where
|
where
|
||||||
Lhs: HdlPartialEqImpl<Rhs>,
|
Lhs: HdlPartialEqImpl<Rhs>,
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::TRY_STRUCTURAL_EQ;
|
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
@ -389,11 +387,6 @@ where
|
||||||
}
|
}
|
||||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
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()
|
lhs.into_iter()
|
||||||
.zip(rhs)
|
.zip(rhs)
|
||||||
.map(|(l, r)| l.cmp_eq(r))
|
.map(|(l, r)| l.cmp_eq(r))
|
||||||
|
|
@ -403,11 +396,6 @@ where
|
||||||
}
|
}
|
||||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
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()
|
lhs.into_iter()
|
||||||
.zip(rhs)
|
.zip(rhs)
|
||||||
.map(|(l, r)| l.cmp_ne(r))
|
.map(|(l, r)| l.cmp_ne(r))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
use eyre::{ContextCompat, eyre};
|
use eyre::{ContextCompat, eyre};
|
||||||
use petgraph::{
|
use petgraph::{
|
||||||
algo::{DfsSpace, kosaraju_scc, toposort},
|
algo::{DfsSpace, kosaraju_scc, toposort},
|
||||||
graph::{DiGraph, NodeIndex},
|
graph::DiGraph,
|
||||||
visit::{GraphBase, Visitable},
|
visit::{GraphBase, Visitable},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq};
|
||||||
|
|
@ -465,7 +465,7 @@ impl JobGraph {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("we know there's a cycle");
|
.expect("we know there's a cycle");
|
||||||
let cycle_set = HashSet::<NodeIndex>::from_iter(cycle.iter().copied());
|
let cycle_set = HashSet::from_iter(cycle.iter().copied());
|
||||||
let job = cycle
|
let job = cycle
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|node_id| {
|
.find_map(|node_id| {
|
||||||
|
|
@ -701,7 +701,7 @@ impl JobGraph {
|
||||||
job: DynJob,
|
job: DynJob,
|
||||||
thread: ScopedJoinHandle<'scope, eyre::Result<Vec<JobItem>>>,
|
thread: ScopedJoinHandle<'scope, eyre::Result<Vec<JobItem>>>,
|
||||||
}
|
}
|
||||||
let mut running_jobs = HashMap::<NodeIndex, RunningJob>::default();
|
let mut running_jobs = HashMap::default();
|
||||||
let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel();
|
let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel();
|
||||||
let mut next_finished_job = None;
|
let mut next_finished_job = None;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
expr::{
|
expr::{
|
||||||
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
|
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
|
||||||
Valueless,
|
Valueless,
|
||||||
ops::{ArrayLiteral, BundleLiteral, StructuralEq},
|
ops::{ArrayLiteral, BundleLiteral},
|
||||||
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
|
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
|
||||||
},
|
},
|
||||||
int::{Bool, DynSize},
|
int::{Bool, DynSize},
|
||||||
|
|
@ -708,8 +708,6 @@ macro_rules! impl_tuples {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||||
const TRY_STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::TRY_STRUCTURAL_EQ)*;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
@ -727,11 +725,6 @@ macro_rules! impl_tuples {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
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 ($($lhs_var,)*) = *lhs;
|
||||||
let ($($rhs_var,)*) = *rhs;
|
let ($($rhs_var,)*) = *rhs;
|
||||||
ArrayLiteral::<Bool, DynSize>::new(
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
|
@ -744,11 +737,6 @@ macro_rules! impl_tuples {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||||
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 ($($lhs_var,)*) = *lhs;
|
||||||
let ($($rhs_var,)*) = *rhs;
|
let ($($rhs_var,)*) = *rhs;
|
||||||
ArrayLiteral::<Bool, DynSize>::new(
|
ArrayLiteral::<Bool, DynSize>::new(
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,6 @@ expr_enum! {
|
||||||
CastBitsTo(ops::CastBitsTo),
|
CastBitsTo(ops::CastBitsTo),
|
||||||
ToTraceAsString(ops::ToTraceAsString),
|
ToTraceAsString(ops::ToTraceAsString),
|
||||||
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
TraceAsStringAsInner(ops::TraceAsStringAsInner),
|
||||||
StructuralEq(ops::StructuralEq),
|
|
||||||
ModuleIO(ModuleIO<CanonicalType>),
|
ModuleIO(ModuleIO<CanonicalType>),
|
||||||
Instance(Instance<Bundle>),
|
Instance(Instance<Bundle>),
|
||||||
Wire(Wire<CanonicalType>),
|
Wire(Wire<CanonicalType>),
|
||||||
|
|
@ -702,7 +701,6 @@ macro_rules! impl_hdl_cmp {
|
||||||
impl_helper = $HdlCmpImplHelper:ident,
|
impl_helper = $HdlCmpImplHelper:ident,
|
||||||
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
|
||||||
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
|
||||||
$(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)?
|
|
||||||
]
|
]
|
||||||
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
|
||||||
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
|
||||||
|
|
@ -731,8 +729,6 @@ macro_rules! impl_hdl_cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
|
||||||
$(const $TRY_STRUCTURAL_EQ: bool;)?
|
|
||||||
|
|
||||||
$(#[track_caller]
|
$(#[track_caller]
|
||||||
fn $cmp_value_fn(
|
fn $cmp_value_fn(
|
||||||
$cmp_value_lhs: Self,
|
$cmp_value_lhs: Self,
|
||||||
|
|
@ -916,7 +912,6 @@ impl_hdl_cmp! {
|
||||||
#[
|
#[
|
||||||
impl_helper = HdlPartialEqImplHelper,
|
impl_helper = HdlPartialEqImplHelper,
|
||||||
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
impl_helper_sealed = HdlPartialEqImplHelperSealed,
|
||||||
try_structural_eq = TRY_STRUCTURAL_EQ,
|
|
||||||
]
|
]
|
||||||
pub trait HdlPartialEq<Rhs: ValueType>:
|
pub trait HdlPartialEq<Rhs: ValueType>:
|
||||||
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
|
||||||
UIntType, UIntValue,
|
UIntType, UIntValue,
|
||||||
},
|
},
|
||||||
intern::{Intern, Interned, MemoizeGeneric},
|
intern::{Intern, Interned},
|
||||||
phantom_const::{PhantomConst, PhantomConstValue},
|
phantom_const::{PhantomConst, PhantomConstValue},
|
||||||
reset::{
|
reset::{
|
||||||
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
|
||||||
|
|
@ -2984,7 +2984,6 @@ macro_rules! impl_compare_op {
|
||||||
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
|
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
|
||||||
#[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)]
|
#[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)]
|
||||||
#[type($Lhs:ty, $Rhs:ty)]
|
#[type($Lhs:ty, $Rhs:ty)]
|
||||||
$(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])?
|
|
||||||
#[trait($Trait:ident)]
|
#[trait($Trait:ident)]
|
||||||
$(
|
$(
|
||||||
struct $name:ident;
|
struct $name:ident;
|
||||||
|
|
@ -3046,7 +3045,6 @@ macro_rules! impl_compare_op {
|
||||||
})*
|
})*
|
||||||
|
|
||||||
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
|
||||||
$(const $TRY_STRUCTURAL_EQ: bool = true;)?
|
|
||||||
$(fn $value_method(
|
$(fn $value_method(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
|
||||||
|
|
@ -3067,7 +3065,6 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
#[to_dyn_type(lhs => lhs, rhs => rhs)]
|
||||||
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
|
||||||
#[type(Bool, Bool)]
|
#[type(Bool, Bool)]
|
||||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3091,7 +3088,6 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
||||||
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
|
||||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3116,7 +3112,6 @@ impl_compare_op! {
|
||||||
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
|
||||||
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
|
||||||
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
|
||||||
#[try_structural_eq = TRY_STRUCTURAL_EQ]
|
|
||||||
#[trait(HdlPartialEqImpl)]
|
#[trait(HdlPartialEqImpl)]
|
||||||
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
|
||||||
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
|
||||||
|
|
@ -3138,8 +3133,6 @@ impl_compare_op! {
|
||||||
macro_rules! impl_compare_forwards_to_bool {
|
macro_rules! impl_compare_forwards_to_bool {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl HdlPartialEqImpl<Self> for $ty {
|
impl HdlPartialEqImpl<Self> for $ty {
|
||||||
const TRY_STRUCTURAL_EQ: bool = true;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -4955,270 +4948,3 @@ impl ToExpr for SimIoForGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct StructuralEqFlags {
|
|
||||||
pub assume_padding_is_zeroed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StructuralEqFlags {
|
|
||||||
pub const DEFAULT: Self = Self {
|
|
||||||
assume_padding_is_zeroed: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for StructuralEqFlags {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::DEFAULT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum StructuralEqError {
|
|
||||||
TypesAreNotEqual {
|
|
||||||
lhs: CanonicalType,
|
|
||||||
rhs: CanonicalType,
|
|
||||||
},
|
|
||||||
TypeContainsSimOnly {
|
|
||||||
ty: CanonicalType,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for StructuralEqError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::TypesAreNotEqual { lhs, rhs } => write!(
|
|
||||||
f,
|
|
||||||
"StructuralEq lhs type must be the same as rhs type:\nlhs: {lhs:#?}\nrhs: {rhs:#?}\n",
|
|
||||||
),
|
|
||||||
Self::TypeContainsSimOnly { ty } => write!(
|
|
||||||
f,
|
|
||||||
"StructuralEq input type must not contain SimOnly type: {ty:#?}",
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
|
||||||
pub struct StructuralEq {
|
|
||||||
lhs: Expr<CanonicalType>,
|
|
||||||
rhs: Expr<CanonicalType>,
|
|
||||||
flags: StructuralEqFlags,
|
|
||||||
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StructuralEq {
|
|
||||||
fn literal_eq(
|
|
||||||
ty: CanonicalType,
|
|
||||||
l: Interned<BitSlice>,
|
|
||||||
r: Interned<BitSlice>,
|
|
||||||
) -> Result<bool, NotALiteralExpr> {
|
|
||||||
enum PairRefOrInternedBitSlice<'a> {
|
|
||||||
Ref(&'a BitSlice, &'a BitSlice),
|
|
||||||
Interned(Interned<BitSlice>, Interned<BitSlice>),
|
|
||||||
}
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
struct MyMemoize(CanonicalType);
|
|
||||||
impl MemoizeGeneric for MyMemoize {
|
|
||||||
type InputRef<'a> = (&'a BitSlice, &'a BitSlice);
|
|
||||||
type InputOwned = (Interned<BitSlice>, Interned<BitSlice>);
|
|
||||||
type InputCow<'a> = PairRefOrInternedBitSlice<'a>;
|
|
||||||
type Output = Result<bool, NotALiteralExpr>;
|
|
||||||
|
|
||||||
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
|
|
||||||
a == b
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
|
||||||
let (l, r) = input;
|
|
||||||
(l, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
|
|
||||||
match input {
|
|
||||||
PairRefOrInternedBitSlice::Ref(l, r) => (l.intern(), r.intern()),
|
|
||||||
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
|
|
||||||
match input {
|
|
||||||
PairRefOrInternedBitSlice::Ref(l, r) => (l, r),
|
|
||||||
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
|
|
||||||
let (l, r) = input;
|
|
||||||
PairRefOrInternedBitSlice::Interned(l, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
|
|
||||||
let (l, r) = input;
|
|
||||||
PairRefOrInternedBitSlice::Ref(l, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
|
|
||||||
let (mut l, mut r) = input;
|
|
||||||
match self.0 {
|
|
||||||
CanonicalType::UInt(_)
|
|
||||||
| CanonicalType::SInt(_)
|
|
||||||
| CanonicalType::Bool(_)
|
|
||||||
| CanonicalType::AsyncReset(_)
|
|
||||||
| CanonicalType::SyncReset(_)
|
|
||||||
| CanonicalType::Reset(_)
|
|
||||||
| CanonicalType::Clock(_)
|
|
||||||
| CanonicalType::PhantomConst(_) => Ok(l == r),
|
|
||||||
CanonicalType::Array(ty) => {
|
|
||||||
let element_ty = ty.element();
|
|
||||||
let element_bit_width = element_ty.bit_width();
|
|
||||||
let mut eq = true;
|
|
||||||
for element_index in 0..ty.len() {
|
|
||||||
if !Self(element_ty).get((
|
|
||||||
&l[element_bit_width * element_index..][..element_bit_width],
|
|
||||||
&r[element_bit_width * element_index..][..element_bit_width],
|
|
||||||
))? {
|
|
||||||
eq = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(eq)
|
|
||||||
}
|
|
||||||
CanonicalType::Enum(ty) => {
|
|
||||||
let discriminant_bit_width = ty.discriminant_bit_width();
|
|
||||||
let (l_discriminant_bits, l_body_bits) = l.split_at(discriminant_bit_width);
|
|
||||||
let (r_discriminant_bits, r_body_bits) = r.split_at(discriminant_bit_width);
|
|
||||||
if l_discriminant_bits != r_discriminant_bits {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
let mut discriminant = 0usize;
|
|
||||||
discriminant.view_bits_mut::<Lsb0>()[..l_discriminant_bits.len()]
|
|
||||||
.copy_from_bitslice(l_discriminant_bits);
|
|
||||||
match ty.variants().get(discriminant) {
|
|
||||||
Some(&EnumVariant {
|
|
||||||
name: _,
|
|
||||||
ty: Some(variant_ty),
|
|
||||||
}) => {
|
|
||||||
let variant_bit_width = variant_ty.bit_width();
|
|
||||||
Self(variant_ty).get((
|
|
||||||
&l_body_bits[..variant_bit_width],
|
|
||||||
&r_body_bits[..variant_bit_width],
|
|
||||||
))
|
|
||||||
}
|
|
||||||
Some(EnumVariant { name: _, ty: None }) => Ok(true),
|
|
||||||
None => Err(NotALiteralExpr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CanonicalType::Bundle(ty) => {
|
|
||||||
let mut eq = true;
|
|
||||||
for field in &ty.fields() {
|
|
||||||
let field_bit_width = field.ty.bit_width();
|
|
||||||
let l_field;
|
|
||||||
let r_field;
|
|
||||||
(l_field, l) = l.split_at(field_bit_width);
|
|
||||||
(r_field, r) = r.split_at(field_bit_width);
|
|
||||||
if !Self(field.ty).get((l_field, r_field))? {
|
|
||||||
eq = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(eq)
|
|
||||||
}
|
|
||||||
CanonicalType::DynSimOnly(_) => unreachable!("doesn't have literal_bits"),
|
|
||||||
CanonicalType::TraceAsString(ty) => Self(ty.inner_ty()).get((l, r)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MyMemoize(ty).get_owned((l, r))
|
|
||||||
}
|
|
||||||
#[track_caller]
|
|
||||||
pub fn new(lhs: Expr<CanonicalType>, rhs: Expr<CanonicalType>) -> Self {
|
|
||||||
Self::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
|
||||||
}
|
|
||||||
#[track_caller]
|
|
||||||
pub fn with_flags(
|
|
||||||
lhs: Expr<CanonicalType>,
|
|
||||||
rhs: Expr<CanonicalType>,
|
|
||||||
flags: StructuralEqFlags,
|
|
||||||
) -> Self {
|
|
||||||
match Self::try_with_flags(lhs, rhs, flags) {
|
|
||||||
Ok(retval) => retval,
|
|
||||||
Err(e) => panic!("{e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn try_new(
|
|
||||||
lhs: Expr<CanonicalType>,
|
|
||||||
rhs: Expr<CanonicalType>,
|
|
||||||
) -> Result<Self, StructuralEqError> {
|
|
||||||
Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
|
|
||||||
}
|
|
||||||
pub fn try_with_flags(
|
|
||||||
lhs: Expr<CanonicalType>,
|
|
||||||
rhs: Expr<CanonicalType>,
|
|
||||||
flags: StructuralEqFlags,
|
|
||||||
) -> Result<Self, StructuralEqError> {
|
|
||||||
let ty = lhs.ty();
|
|
||||||
let rhs_ty = rhs.ty();
|
|
||||||
if ty != rhs_ty {
|
|
||||||
return Err(StructuralEqError::TypesAreNotEqual {
|
|
||||||
lhs: ty,
|
|
||||||
rhs: rhs_ty,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ty.contains_sim_only() {
|
|
||||||
return Err(StructuralEqError::TypeContainsSimOnly { ty });
|
|
||||||
}
|
|
||||||
Ok(Self {
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
flags,
|
|
||||||
literal_bits: lhs.to_literal_bits().and_then(|lhs| {
|
|
||||||
let rhs = rhs.to_literal_bits()?;
|
|
||||||
if flags.assume_padding_is_zeroed {
|
|
||||||
lhs == rhs
|
|
||||||
} else {
|
|
||||||
Self::literal_eq(ty, lhs, rhs)?
|
|
||||||
}
|
|
||||||
.to_literal_bits()
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn lhs(self) -> Expr<CanonicalType> {
|
|
||||||
self.lhs
|
|
||||||
}
|
|
||||||
pub fn rhs(self) -> Expr<CanonicalType> {
|
|
||||||
self.rhs
|
|
||||||
}
|
|
||||||
pub fn flags(self) -> StructuralEqFlags {
|
|
||||||
self.flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToLiteralBits for StructuralEq {
|
|
||||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
||||||
self.literal_bits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_get_target_none!([] StructuralEq);
|
|
||||||
|
|
||||||
impl ValueType for StructuralEq {
|
|
||||||
type Type = Bool;
|
|
||||||
type ValueCategory = ValueCategoryExpr;
|
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
|
||||||
Bool
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToExpr for StructuralEq {
|
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
|
||||||
Expr {
|
|
||||||
__enum: ExprEnum::StructuralEq(*self).intern(),
|
|
||||||
__ty: Bool,
|
|
||||||
__flow: Flow::Source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ pub struct TargetPathToTraceAsString {
|
||||||
|
|
||||||
impl fmt::Display for TargetPathToTraceAsString {
|
impl fmt::Display for TargetPathToTraceAsString {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, ".to_trace_as_string()")
|
write!(f, ".to_trace_as_string(...)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
bundle::{BundleField, BundleType},
|
bundle::{BundleField, BundleType},
|
||||||
enum_::{EnumType, EnumVariant},
|
enum_::{EnumType, EnumVariant},
|
||||||
expr::{
|
expr::{
|
||||||
CastToImpl, ExprEnum,
|
ExprEnum,
|
||||||
ops::{self, VariantAccess},
|
ops::{self, VariantAccess},
|
||||||
target::{
|
target::{
|
||||||
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
||||||
|
|
@ -389,7 +389,6 @@ struct BlockDefinitionsCache {
|
||||||
cast_bits_to_array_exprs: RefCell<HashMap<(String, Array), String>>,
|
cast_bits_to_array_exprs: RefCell<HashMap<(String, Array), String>>,
|
||||||
cast_bits_to_phantom_const_exprs: RefCell<HashMap<(String, PhantomConst), String>>,
|
cast_bits_to_phantom_const_exprs: RefCell<HashMap<(String, PhantomConst), String>>,
|
||||||
per_module_formal_inputs: RefCell<HashMap<(FormalInput, bool), String>>,
|
per_module_formal_inputs: RefCell<HashMap<(FormalInput, bool), String>>,
|
||||||
structural_eq_exprs: RefCell<HashMap<(String, String), String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockDefinitions<'a> {
|
struct BlockDefinitions<'a> {
|
||||||
|
|
@ -1775,143 +1774,6 @@ endmodule
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn expr_structural_eq_bit<T: CastToImpl<Bool>>(
|
|
||||||
&mut self,
|
|
||||||
lhs: Expr<CanonicalType>,
|
|
||||||
rhs: Expr<CanonicalType>,
|
|
||||||
definitions: &BlockDefinitions<'_>,
|
|
||||||
const_ty: bool,
|
|
||||||
) -> Result<String> {
|
|
||||||
self.expr_binary(
|
|
||||||
"eq",
|
|
||||||
Expr::<T>::from_canonical(lhs).cast_to(Bool),
|
|
||||||
Expr::<T>::from_canonical(rhs).cast_to(Bool),
|
|
||||||
definitions,
|
|
||||||
const_ty,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn expr_structural_eq(
|
|
||||||
&mut self,
|
|
||||||
ty: CanonicalType,
|
|
||||||
lhs: String,
|
|
||||||
rhs: String,
|
|
||||||
definitions: &BlockDefinitions<'_>,
|
|
||||||
const_ty: bool,
|
|
||||||
) -> Result<String> {
|
|
||||||
match ty {
|
|
||||||
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
|
|
||||||
Ok(format!("eq({lhs}, {rhs})"))
|
|
||||||
}
|
|
||||||
CanonicalType::Array(ty) => {
|
|
||||||
if ty.len() == 1 {
|
|
||||||
return self.expr_structural_eq(
|
|
||||||
ty.element(),
|
|
||||||
lhs + "[0]",
|
|
||||||
rhs + "[0]",
|
|
||||||
definitions,
|
|
||||||
const_ty,
|
|
||||||
);
|
|
||||||
} else if ty.is_empty() {
|
|
||||||
return Ok(self.bool_literal(true));
|
|
||||||
}
|
|
||||||
definitions.get_or_write_definition(
|
|
||||||
(lhs, rhs),
|
|
||||||
|c| &c.structural_eq_exprs,
|
|
||||||
|definitions, (lhs, rhs)| {
|
|
||||||
let mut retval = None;
|
|
||||||
for array_index in 0..ty.len() {
|
|
||||||
let element_eq = self.expr_structural_eq(
|
|
||||||
ty.element(),
|
|
||||||
format!("{lhs}[{array_index}]"),
|
|
||||||
format!("{rhs}[{array_index}]"),
|
|
||||||
&definitions,
|
|
||||||
const_ty,
|
|
||||||
)?;
|
|
||||||
retval = match retval {
|
|
||||||
Some(old_eq) => {
|
|
||||||
let ident = self.module.ns.make_new("_array_structural_eq");
|
|
||||||
definitions
|
|
||||||
.add_definition_line(format_args!("wire {ident}: UInt<1>"));
|
|
||||||
definitions.add_definition_line(format_args!(
|
|
||||||
"connect {ident}, and({old_eq}, {element_eq})"
|
|
||||||
));
|
|
||||||
Some(ident.to_string())
|
|
||||||
}
|
|
||||||
None => Some(element_eq),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(retval.expect("known to be Some"))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
CanonicalType::Enum(ty) => {
|
|
||||||
let lhs = self.expr_cast_enum_to_bits(
|
|
||||||
lhs,
|
|
||||||
ty,
|
|
||||||
definitions,
|
|
||||||
Indent {
|
|
||||||
indent_depth: &Cell::new(0),
|
|
||||||
indent: self.indent.indent,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let rhs = self.expr_cast_enum_to_bits(
|
|
||||||
rhs,
|
|
||||||
ty,
|
|
||||||
definitions,
|
|
||||||
Indent {
|
|
||||||
indent_depth: &Cell::new(0),
|
|
||||||
indent: self.indent.indent,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
Ok(format!("eq({lhs}, {rhs})"))
|
|
||||||
}
|
|
||||||
CanonicalType::Bundle(ty) => {
|
|
||||||
let fields = ty.fields();
|
|
||||||
if fields.is_empty() {
|
|
||||||
return Ok(self.bool_literal(true));
|
|
||||||
}
|
|
||||||
definitions.get_or_write_definition(
|
|
||||||
(lhs, rhs),
|
|
||||||
|c| &c.structural_eq_exprs,
|
|
||||||
|definitions, (lhs, rhs)| {
|
|
||||||
let mut retval = None;
|
|
||||||
for field in fields {
|
|
||||||
let field_ident = self.type_state.get_bundle_field(ty, field.name)?;
|
|
||||||
let field_eq = self.expr_structural_eq(
|
|
||||||
field.ty,
|
|
||||||
format!("{lhs}.{field_ident}"),
|
|
||||||
format!("{rhs}.{field_ident}"),
|
|
||||||
&definitions,
|
|
||||||
const_ty,
|
|
||||||
)?;
|
|
||||||
retval = match retval {
|
|
||||||
Some(old_eq) => {
|
|
||||||
let ident = self.module.ns.make_new("_bundle_structural_eq");
|
|
||||||
definitions
|
|
||||||
.add_definition_line(format_args!("wire {ident}: UInt<1>"));
|
|
||||||
definitions.add_definition_line(format_args!(
|
|
||||||
"connect {ident}, and({old_eq}, {field_eq})"
|
|
||||||
));
|
|
||||||
Some(ident.to_string())
|
|
||||||
}
|
|
||||||
None => Some(field_eq),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(retval.expect("known to be Some"))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
CanonicalType::AsyncReset(_)
|
|
||||||
| CanonicalType::SyncReset(_)
|
|
||||||
| CanonicalType::Reset(_)
|
|
||||||
| CanonicalType::Clock(_) => Ok(format!("eq(asUInt({lhs}), asUInt({rhs}))")),
|
|
||||||
CanonicalType::PhantomConst(_) => Ok(self.bool_literal(true)),
|
|
||||||
CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()),
|
|
||||||
CanonicalType::TraceAsString(ty) => {
|
|
||||||
self.expr_structural_eq(ty.inner_ty(), lhs, rhs, definitions, const_ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn expr(
|
fn expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: Expr<CanonicalType>,
|
expr: Expr<CanonicalType>,
|
||||||
|
|
@ -2255,13 +2117,6 @@ endmodule
|
||||||
ExprEnum::TraceAsStringAsInner(expr) => {
|
ExprEnum::TraceAsStringAsInner(expr) => {
|
||||||
self.expr(Expr::canonical(expr.arg()), definitions, const_ty)
|
self.expr(Expr::canonical(expr.arg()), definitions, const_ty)
|
||||||
}
|
}
|
||||||
ExprEnum::StructuralEq(expr) => {
|
|
||||||
let ty = expr.lhs().ty();
|
|
||||||
assert_eq!(ty, expr.rhs().ty());
|
|
||||||
let lhs = self.expr(expr.lhs(), definitions, const_ty)?;
|
|
||||||
let rhs = self.expr(expr.rhs(), definitions, const_ty)?;
|
|
||||||
self.expr_structural_eq(ty, lhs, rhs, definitions, const_ty)
|
|
||||||
}
|
|
||||||
ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()),
|
ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()),
|
||||||
ExprEnum::Instance(expr) => {
|
ExprEnum::Instance(expr) => {
|
||||||
assert!(!const_ty, "not a constant");
|
assert!(!const_ty, "not a constant");
|
||||||
|
|
|
||||||
|
|
@ -177,8 +177,6 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
||||||
const TRY_STRUCTURAL_EQ: bool = true;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -572,8 +570,6 @@ macro_rules! define_uint_in_range_type {
|
||||||
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: bool = true;
|
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
@ -661,8 +657,6 @@ macro_rules! define_uint_in_range_type {
|
||||||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
||||||
for $UIntInRangeType<Start, End>
|
for $UIntInRangeType<Start, End>
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: bool = false;
|
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
@ -682,8 +676,6 @@ macro_rules! define_uint_in_range_type {
|
||||||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
||||||
for UIntType<Width>
|
for UIntType<Width>
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: bool = false;
|
|
||||||
|
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
lhs_value: Cow<'_, Self::SimValue>,
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
|
|
||||||
|
|
@ -2206,7 +2206,6 @@ impl transform::visit::Visitor for AssertExprValidity<'_> {
|
||||||
| ExprEnum::CastBitsTo(_)
|
| ExprEnum::CastBitsTo(_)
|
||||||
| ExprEnum::ToTraceAsString(_)
|
| ExprEnum::ToTraceAsString(_)
|
||||||
| ExprEnum::TraceAsStringAsInner(_)
|
| ExprEnum::TraceAsStringAsInner(_)
|
||||||
| ExprEnum::StructuralEq(_)
|
|
||||||
| ExprEnum::FormalInput(_) => v.default_visit(self),
|
| ExprEnum::FormalInput(_) => v.default_visit(self),
|
||||||
ExprEnum::VariantAccess(_)
|
ExprEnum::VariantAccess(_)
|
||||||
| ExprEnum::ModuleIO(_)
|
| ExprEnum::ModuleIO(_)
|
||||||
|
|
@ -2248,7 +2247,7 @@ impl<T: BundleType> Module<T> {
|
||||||
clocks_for_past,
|
clocks_for_past,
|
||||||
simulation: Some(simulation),
|
simulation: Some(simulation),
|
||||||
}) => {
|
}) => {
|
||||||
let mut clocks_for_past_set = HashSet::<Target>::default();
|
let mut clocks_for_past_set = HashSet::default();
|
||||||
*clocks_for_past = clocks_for_past
|
*clocks_for_past = clocks_for_past
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
|
@ -2269,9 +2268,7 @@ impl<T: BundleType> Module<T> {
|
||||||
}
|
}
|
||||||
if simulation.sim_io_to_generator_map.len() > module_io.len() {
|
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
|
// 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::<ModuleIO<CanonicalType>>::from_iter(
|
let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io));
|
||||||
module_io.iter().map(|v| v.module_io),
|
|
||||||
);
|
|
||||||
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
|
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
|
||||||
if !module_io_set.contains(&**sim_io) {
|
if !module_io_set.contains(&**sim_io) {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod deduce_resets;
|
pub mod deduce_resets;
|
||||||
pub mod deduce_structural_eq_flags;
|
|
||||||
pub mod simplify_enums;
|
pub mod simplify_enums;
|
||||||
pub mod simplify_memories;
|
pub mod simplify_memories;
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
|
||||||
|
|
@ -1208,7 +1208,6 @@ impl<P: Pass> RunPass<P> for ExprEnum {
|
||||||
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
|
||||||
}
|
}
|
||||||
ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
|
||||||
ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
|
||||||
|
|
@ -1654,35 +1653,6 @@ impl RunPassExpr for ops::ToTraceAsString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunPassExpr for ops::StructuralEq {
|
|
||||||
type Args<'a> = [Expr<CanonicalType>; 2];
|
|
||||||
|
|
||||||
fn args<'a>(&'a self) -> Self::Args<'a> {
|
|
||||||
[self.lhs(), self.rhs()]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn source_location(&self) -> Option<SourceLocation> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn union_parts(
|
|
||||||
&self,
|
|
||||||
_resets: Resets,
|
|
||||||
args_resets: Vec<Resets>,
|
|
||||||
mut pass_args: PassArgs<'_, BuildResetGraph>,
|
|
||||||
) -> Result<(), DeduceResetsError> {
|
|
||||||
pass_args.union(args_resets[0], args_resets[1], None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(
|
|
||||||
&self,
|
|
||||||
_ty: CanonicalType,
|
|
||||||
new_args: Vec<Expr<CanonicalType>>,
|
|
||||||
) -> Result<Self, DeduceResetsError> {
|
|
||||||
Ok(Self::with_flags(new_args[0], new_args[1], self.flags()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunPassExpr for ModuleIO<CanonicalType> {
|
impl RunPassExpr for ModuleIO<CanonicalType> {
|
||||||
type Args<'a> = [Expr<CanonicalType>; 0];
|
type Args<'a> = [Expr<CanonicalType>; 0];
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,26 +1,28 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{BundleField, BundleType},
|
array::{Array, ArrayType},
|
||||||
enum_::{EnumType, EnumVariant},
|
bundle::{Bundle, BundleField, BundleType},
|
||||||
|
enum_::{Enum, EnumType, EnumVariant},
|
||||||
expr::{
|
expr::{
|
||||||
ExprEnum,
|
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
|
||||||
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
|
ops::{self, EnumLiteral},
|
||||||
},
|
},
|
||||||
|
hdl,
|
||||||
|
int::UInt,
|
||||||
intern::{Intern, InternSlice, Interned, Memoize},
|
intern::{Intern, InternSlice, Interned, Memoize},
|
||||||
memory::{DynPortType, MemPort},
|
memory::{DynPortType, Mem, MemPort},
|
||||||
module::{
|
module::{
|
||||||
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
|
||||||
transform::{
|
transform::visit::{Fold, Folder},
|
||||||
deduce_structural_eq_flags::deduce_structural_eq_flags,
|
|
||||||
visit::{Fold, Folder},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
prelude::*,
|
source_location::SourceLocation,
|
||||||
|
ty::{CanonicalType, TraceAsString, Type},
|
||||||
util::HashMap,
|
util::HashMap,
|
||||||
|
wire::Wire,
|
||||||
};
|
};
|
||||||
|
use core::fmt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SimplifyEnumsError {
|
pub enum SimplifyEnumsError {
|
||||||
|
|
@ -95,7 +97,6 @@ enum EnumTypeState {
|
||||||
struct ModuleState {
|
struct ModuleState {
|
||||||
module_name: NameId,
|
module_name: NameId,
|
||||||
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
expr_cache: HashMap<ExprEnum, ExprEnum>,
|
||||||
source_location: SourceLocation,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleState {
|
impl ModuleState {
|
||||||
|
|
@ -109,45 +110,6 @@ struct State {
|
||||||
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
module_state_stack: Vec<ModuleState>,
|
module_state_stack: Vec<ModuleState>,
|
||||||
new_prefix_stmts_for_block: Vec<Stmt>,
|
|
||||||
new_suffix_stmts_for_block: Vec<Stmt>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BlockScope<'a> {
|
|
||||||
state: &'a mut State,
|
|
||||||
parent_new_prefix_stmts_for_block: Vec<Stmt>,
|
|
||||||
parent_new_suffix_stmts_for_block: Vec<Stmt>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> BlockScope<'a> {
|
|
||||||
fn new(
|
|
||||||
state: &'a mut State,
|
|
||||||
new_prefix_stmts_for_block: Vec<Stmt>,
|
|
||||||
new_suffix_stmts_for_block: Vec<Stmt>,
|
|
||||||
) -> Self {
|
|
||||||
let parent_new_prefix_stmts_for_block = std::mem::replace(
|
|
||||||
&mut state.new_prefix_stmts_for_block,
|
|
||||||
new_prefix_stmts_for_block,
|
|
||||||
);
|
|
||||||
let parent_new_suffix_stmts_for_block = std::mem::replace(
|
|
||||||
&mut state.new_suffix_stmts_for_block,
|
|
||||||
new_suffix_stmts_for_block,
|
|
||||||
);
|
|
||||||
Self {
|
|
||||||
state,
|
|
||||||
parent_new_prefix_stmts_for_block,
|
|
||||||
parent_new_suffix_stmts_for_block,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for BlockScope<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.state.new_prefix_stmts_for_block =
|
|
||||||
std::mem::take(&mut self.parent_new_prefix_stmts_for_block);
|
|
||||||
self.state.new_suffix_stmts_for_block =
|
|
||||||
std::mem::take(&mut self.parent_new_suffix_stmts_for_block);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
|
@ -587,185 +549,6 @@ impl State {
|
||||||
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
| CanonicalType::DynSimOnly(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn handle_enum_structural_eq(
|
|
||||||
&mut self,
|
|
||||||
unfolded_ty: Enum,
|
|
||||||
folded_lhs: Expr<CanonicalType>,
|
|
||||||
folded_rhs: Expr<CanonicalType>,
|
|
||||||
flags: StructuralEqFlags,
|
|
||||||
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
|
||||||
if flags.assume_padding_is_zeroed {
|
|
||||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
|
||||||
}
|
|
||||||
let enum_type_state = self.get_or_make_enum_type_state(unfolded_ty)?;
|
|
||||||
if let EnumTypeState::Unchanged = enum_type_state {
|
|
||||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
|
||||||
}
|
|
||||||
let module_state = self.module_state_stack.last_mut().unwrap();
|
|
||||||
let source_location = module_state.source_location;
|
|
||||||
let output_wire = Wire::new_unchecked(
|
|
||||||
module_state.gen_name("__enum_structural_eq"),
|
|
||||||
source_location,
|
|
||||||
Bool,
|
|
||||||
);
|
|
||||||
self.new_prefix_stmts_for_block.push(
|
|
||||||
StmtWire {
|
|
||||||
annotations: Interned::default(),
|
|
||||||
wire: output_wire.canonical(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
let output_wire = output_wire.to_expr();
|
|
||||||
self.new_suffix_stmts_for_block.push(
|
|
||||||
StmtConnect {
|
|
||||||
lhs: Expr::canonical(output_wire),
|
|
||||||
rhs: Expr::canonical(false.to_expr()),
|
|
||||||
source_location,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
let tags_eq = match enum_type_state {
|
|
||||||
EnumTypeState::TagEnumAndBody(_) => StructuralEq::with_flags(
|
|
||||||
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_lhs).tag),
|
|
||||||
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_rhs).tag),
|
|
||||||
StructuralEqFlags {
|
|
||||||
assume_padding_is_zeroed: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.to_expr(),
|
|
||||||
EnumTypeState::TagUIntAndBody(_) => {
|
|
||||||
let lhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_lhs).tag;
|
|
||||||
let rhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_rhs).tag;
|
|
||||||
lhs.cmp_eq(rhs)
|
|
||||||
}
|
|
||||||
EnumTypeState::UInt(_) => {
|
|
||||||
let lhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_lhs)
|
|
||||||
[..unfolded_ty.discriminant_bit_width()];
|
|
||||||
let rhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_rhs)
|
|
||||||
[..unfolded_ty.discriminant_bit_width()];
|
|
||||||
lhs_int_tag_expr.cmp_eq(rhs_int_tag_expr)
|
|
||||||
}
|
|
||||||
EnumTypeState::Unchanged => unreachable!(),
|
|
||||||
};
|
|
||||||
let mut match_arms = Vec::with_capacity(unfolded_ty.variants().len());
|
|
||||||
for (variant_index, variant) in unfolded_ty.variants().iter().enumerate() {
|
|
||||||
let block_scope = BlockScope::new(self, vec![], vec![]);
|
|
||||||
let this = &mut *block_scope.state;
|
|
||||||
let eq = if let Some(variant_ty) = variant.ty {
|
|
||||||
let folded_lhs =
|
|
||||||
this.handle_variant_access(unfolded_ty, folded_lhs, variant_index)?;
|
|
||||||
let folded_rhs =
|
|
||||||
this.handle_variant_access(unfolded_ty, folded_rhs, variant_index)?;
|
|
||||||
this.handle_structural_eq(variant_ty, folded_lhs, folded_rhs, flags)?
|
|
||||||
} else {
|
|
||||||
true.to_expr()
|
|
||||||
};
|
|
||||||
match_arms.push(Block {
|
|
||||||
memories: [].intern_slice(),
|
|
||||||
stmts: this
|
|
||||||
.new_prefix_stmts_for_block
|
|
||||||
.drain(..)
|
|
||||||
.chain([StmtConnect {
|
|
||||||
lhs: Expr::canonical(output_wire),
|
|
||||||
rhs: Expr::canonical(eq),
|
|
||||||
source_location,
|
|
||||||
}
|
|
||||||
.into()])
|
|
||||||
.chain(this.new_suffix_stmts_for_block.drain(..))
|
|
||||||
.collect(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let match_stmt =
|
|
||||||
self.handle_match(unfolded_ty, folded_lhs, source_location, &match_arms)?;
|
|
||||||
self.new_suffix_stmts_for_block.push(
|
|
||||||
StmtIf {
|
|
||||||
cond: tags_eq,
|
|
||||||
source_location,
|
|
||||||
blocks: [
|
|
||||||
Block {
|
|
||||||
memories: [].intern_slice(),
|
|
||||||
stmts: [match_stmt].intern_slice(),
|
|
||||||
},
|
|
||||||
Block {
|
|
||||||
memories: [].intern_slice(),
|
|
||||||
stmts: [].intern_slice(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
Ok(output_wire)
|
|
||||||
}
|
|
||||||
fn handle_structural_eq(
|
|
||||||
&mut self,
|
|
||||||
unfolded_ty: CanonicalType,
|
|
||||||
folded_lhs: Expr<CanonicalType>,
|
|
||||||
folded_rhs: Expr<CanonicalType>,
|
|
||||||
flags: StructuralEqFlags,
|
|
||||||
) -> Result<Expr<Bool>, SimplifyEnumsError> {
|
|
||||||
if !contains_any_enum_types(unfolded_ty) {
|
|
||||||
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
|
|
||||||
}
|
|
||||||
match unfolded_ty {
|
|
||||||
CanonicalType::Array(unfolded_ty) => {
|
|
||||||
let unfolded_element_ty = unfolded_ty.element();
|
|
||||||
let mut retval = None;
|
|
||||||
for i in 0..unfolded_ty.len() {
|
|
||||||
let element_eq = self.handle_structural_eq(
|
|
||||||
unfolded_element_ty,
|
|
||||||
ops::ArrayIndex::new(Expr::from_canonical(folded_lhs), i).to_expr(),
|
|
||||||
ops::ArrayIndex::new(Expr::from_canonical(folded_rhs), i).to_expr(),
|
|
||||||
flags,
|
|
||||||
)?;
|
|
||||||
retval = Some(match retval {
|
|
||||||
Some(old_eq) => old_eq & element_eq,
|
|
||||||
None => element_eq,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(retval.unwrap_or_else(|| {
|
|
||||||
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
CanonicalType::Enum(unfolded_ty) => {
|
|
||||||
self.handle_enum_structural_eq(unfolded_ty, folded_lhs, folded_rhs, flags)
|
|
||||||
}
|
|
||||||
CanonicalType::Bundle(unfolded_ty) => {
|
|
||||||
let mut retval = None;
|
|
||||||
for (i, field) in unfolded_ty.fields().iter().enumerate() {
|
|
||||||
let field_eq = self.handle_structural_eq(
|
|
||||||
field.ty,
|
|
||||||
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_lhs), i)
|
|
||||||
.to_expr(),
|
|
||||||
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_rhs), i)
|
|
||||||
.to_expr(),
|
|
||||||
flags,
|
|
||||||
)?;
|
|
||||||
retval = Some(match retval {
|
|
||||||
Some(old_eq) => old_eq & field_eq,
|
|
||||||
None => field_eq,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(retval.unwrap_or_else(|| {
|
|
||||||
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
CanonicalType::TraceAsString(unfolded_ty) => self.handle_structural_eq(
|
|
||||||
unfolded_ty.inner_ty(),
|
|
||||||
*Expr::<TraceAsString>::from_canonical(folded_lhs),
|
|
||||||
*Expr::<TraceAsString>::from_canonical(folded_rhs),
|
|
||||||
flags,
|
|
||||||
),
|
|
||||||
CanonicalType::UInt(_)
|
|
||||||
| CanonicalType::SInt(_)
|
|
||||||
| CanonicalType::Bool(_)
|
|
||||||
| CanonicalType::AsyncReset(_)
|
|
||||||
| CanonicalType::SyncReset(_)
|
|
||||||
| CanonicalType::Reset(_)
|
|
||||||
| CanonicalType::Clock(_)
|
|
||||||
| CanonicalType::PhantomConst(_)
|
|
||||||
| CanonicalType::DynSimOnly(_) => unreachable!("doesn't contain any enum types"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_port(
|
fn connect_port(
|
||||||
|
|
@ -894,7 +677,6 @@ impl Folder for State {
|
||||||
self.module_state_stack.push(ModuleState {
|
self.module_state_stack.push(ModuleState {
|
||||||
module_name: v.name_id(),
|
module_name: v.name_id(),
|
||||||
expr_cache: HashMap::default(),
|
expr_cache: HashMap::default(),
|
||||||
source_location: v.source_location(),
|
|
||||||
});
|
});
|
||||||
let retval = Fold::default_fold(v, self);
|
let retval = Fold::default_fold(v, self);
|
||||||
self.module_state_stack.pop();
|
self.module_state_stack.pop();
|
||||||
|
|
@ -928,18 +710,6 @@ impl Folder for State {
|
||||||
op.variant_index(),
|
op.variant_index(),
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
ExprEnum::StructuralEq(op) => {
|
|
||||||
let ty = op.lhs().ty();
|
|
||||||
assert_eq!(ty, op.rhs().ty());
|
|
||||||
let folded_lhs = Expr::canonical(op.lhs()).fold(self)?;
|
|
||||||
let folded_rhs = Expr::canonical(op.rhs()).fold(self)?;
|
|
||||||
*Expr::expr_enum(self.handle_structural_eq(
|
|
||||||
ty,
|
|
||||||
folded_lhs,
|
|
||||||
folded_rhs,
|
|
||||||
op.flags(),
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
ExprEnum::MemPort(mem_port) => {
|
ExprEnum::MemPort(mem_port) => {
|
||||||
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
|
||||||
ExprEnum::Wire(wire)
|
ExprEnum::Wire(wire)
|
||||||
|
|
@ -1067,13 +837,11 @@ impl Folder for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
|
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
|
||||||
let block_scope = BlockScope::new(self, vec![], vec![]);
|
|
||||||
let this = &mut *block_scope.state;
|
|
||||||
let mut memories = vec![];
|
let mut memories = vec![];
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
for memory in block.memories {
|
for memory in block.memories {
|
||||||
let old_element_ty = memory.array_type().element();
|
let old_element_ty = memory.array_type().element();
|
||||||
let new_element_ty = memory.array_type().element().fold(this)?;
|
let new_element_ty = memory.array_type().element().fold(self)?;
|
||||||
if new_element_ty != old_element_ty {
|
if new_element_ty != old_element_ty {
|
||||||
let mut new_ports = vec![];
|
let mut new_ports = vec![];
|
||||||
for port in memory.ports() {
|
for port in memory.ports() {
|
||||||
|
|
@ -1099,7 +867,7 @@ impl Folder for State {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let wire = Wire::new_unchecked(
|
let wire = Wire::new_unchecked(
|
||||||
this.module_state_stack
|
self.module_state_stack
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.gen_name(&format!(
|
.gen_name(&format!(
|
||||||
|
|
@ -1123,7 +891,7 @@ impl Folder for State {
|
||||||
Expr::canonical(wire.to_expr()),
|
Expr::canonical(wire.to_expr()),
|
||||||
port.source_location(),
|
port.source_location(),
|
||||||
);
|
);
|
||||||
this.replacement_mem_ports.insert(port, wire.canonical());
|
self.replacement_mem_ports.insert(port, wire.canonical());
|
||||||
}
|
}
|
||||||
memories.push(Mem::new_unchecked(
|
memories.push(Mem::new_unchecked(
|
||||||
memory.scoped_name(),
|
memory.scoped_name(),
|
||||||
|
|
@ -1138,12 +906,10 @@ impl Folder for State {
|
||||||
memory.mem_annotations(),
|
memory.mem_annotations(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
memories.push(memory.fold(this)?);
|
memories.push(memory.fold(self)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stmts.extend_from_slice(&block.stmts.fold(this)?);
|
stmts.extend_from_slice(&block.stmts.fold(self)?);
|
||||||
stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..));
|
|
||||||
stmts.extend_from_slice(&this.new_suffix_stmts_for_block);
|
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
memories: Intern::intern_owned(memories),
|
memories: Intern::intern_owned(memories),
|
||||||
stmts: Intern::intern_owned(stmts),
|
stmts: Intern::intern_owned(stmts),
|
||||||
|
|
@ -1265,13 +1031,10 @@ pub fn simplify_enums(
|
||||||
module: Interned<Module<Bundle>>,
|
module: Interned<Module<Bundle>>,
|
||||||
kind: SimplifyEnumsKind,
|
kind: SimplifyEnumsKind,
|
||||||
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
|
||||||
let module = deduce_structural_eq_flags(module);
|
|
||||||
module.fold(&mut State {
|
module.fold(&mut State {
|
||||||
enum_types: HashMap::default(),
|
enum_types: HashMap::default(),
|
||||||
replacement_mem_ports: HashMap::default(),
|
replacement_mem_ports: HashMap::default(),
|
||||||
kind,
|
kind,
|
||||||
module_state_stack: vec![],
|
module_state_stack: vec![],
|
||||||
new_prefix_stmts_for_block: vec![],
|
|
||||||
new_suffix_stmts_for_block: vec![],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -384,8 +384,6 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
||||||
const TRY_STRUCTURAL_EQ: bool = true;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -3145,144 +3145,6 @@ impl Compiler {
|
||||||
insns
|
insns
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn compile_structural_eq(
|
|
||||||
&mut self,
|
|
||||||
instantiated_module_or_global: InstantiatedModuleOrGlobal,
|
|
||||||
expr: ops::StructuralEq,
|
|
||||||
) -> CompiledExpr<CanonicalType> {
|
|
||||||
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::<Array>::from_canonical(expr.lhs());
|
|
||||||
let rhs = Expr::<Array>::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::<Bundle>::from_canonical(expr.lhs());
|
|
||||||
let rhs = Expr::<Bundle>::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::<TraceAsString>::from_canonical(expr.lhs());
|
|
||||||
let rhs = Expr::<TraceAsString>::from_canonical(expr.rhs());
|
|
||||||
self.compile_structural_eq(
|
|
||||||
instantiated_module_or_global,
|
|
||||||
ops::StructuralEq::with_flags(*lhs, *rhs, expr.flags()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn compile_expr(
|
fn compile_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
instantiated_module_or_global: impl Into<InstantiatedModuleOrGlobal>,
|
instantiated_module_or_global: impl Into<InstantiatedModuleOrGlobal>,
|
||||||
|
|
@ -4112,9 +3974,6 @@ impl Compiler {
|
||||||
.compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg()))
|
.compile_expr(instantiated_module_or_global, Expr::canonical(expr.arg()))
|
||||||
.map_ty(TraceAsString::from_canonical)
|
.map_ty(TraceAsString::from_canonical)
|
||||||
.inner(),
|
.inner(),
|
||||||
ExprEnum::StructuralEq(expr) => {
|
|
||||||
self.compile_structural_eq(instantiated_module_or_global, expr)
|
|
||||||
}
|
|
||||||
ExprEnum::ModuleIO(expr) => self
|
ExprEnum::ModuleIO(expr) => self
|
||||||
.compile_value(TargetInInstantiatedModuleOrGlobal::from_target(
|
.compile_value(TargetInInstantiatedModuleOrGlobal::from_target(
|
||||||
instantiated_module_or_global,
|
instantiated_module_or_global,
|
||||||
|
|
|
||||||
|
|
@ -1508,8 +1508,6 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
const TRY_STRUCTURAL_EQ: bool = false;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
@ -1529,8 +1527,6 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||||
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
||||||
for SimOnly<L>
|
for SimOnly<L>
|
||||||
{
|
{
|
||||||
const TRY_STRUCTURAL_EQ: bool = false;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
_lhs: Self,
|
_lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -354,39 +354,6 @@ impl CanonicalType {
|
||||||
}
|
}
|
||||||
MyMemoize.get_owned((self, other))
|
MyMemoize.get_owned((self, other))
|
||||||
}
|
}
|
||||||
pub fn contains_sim_only(self) -> bool {
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
struct MyMemoize;
|
|
||||||
impl Memoize for MyMemoize {
|
|
||||||
type Input = CanonicalType;
|
|
||||||
type InputOwned = CanonicalType;
|
|
||||||
type Output = bool;
|
|
||||||
|
|
||||||
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
||||||
match input {
|
|
||||||
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
CanonicalType::Array(ty) => ty.element().contains_sim_only(),
|
|
||||||
CanonicalType::Enum(ty) => ty
|
|
||||||
.variants()
|
|
||||||
.iter()
|
|
||||||
.any(|v| v.ty.is_some_and(CanonicalType::contains_sim_only)),
|
|
||||||
CanonicalType::Bundle(ty) => {
|
|
||||||
ty.fields().iter().any(|v| v.ty.contains_sim_only())
|
|
||||||
}
|
|
||||||
CanonicalType::AsyncReset(_)
|
|
||||||
| CanonicalType::SyncReset(_)
|
|
||||||
| CanonicalType::Reset(_)
|
|
||||||
| CanonicalType::Clock(_)
|
|
||||||
| CanonicalType::PhantomConst(_) => false,
|
|
||||||
CanonicalType::DynSimOnly(_) => true,
|
|
||||||
CanonicalType::TraceAsString(ty) => ty.inner_ty().contains_sim_only(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MyMemoize.get_owned(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MatchVariantAndInactiveScope: Sized {
|
pub trait MatchVariantAndInactiveScope: Sized {
|
||||||
|
|
@ -1915,8 +1882,6 @@ fn trace_as_string_cow_into_inner_value<T: Type>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
|
||||||
const TRY_STRUCTURAL_EQ: bool = <T as HdlPartialEqImpl<U>>::TRY_STRUCTURAL_EQ;
|
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn cmp_value_eq(
|
fn cmp_value_eq(
|
||||||
lhs: Self,
|
lhs: Self,
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher;
|
||||||
#[cfg(not(feature = "unstable-test-hasher"))]
|
#[cfg(not(feature = "unstable-test-hasher"))]
|
||||||
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
|
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
|
||||||
|
|
||||||
pub(crate) type HashMap<K, V, H = DefaultBuildHasher> = hashbrown::HashMap<K, V, H>;
|
pub(crate) type HashMap<K, V> = hashbrown::HashMap<K, V, DefaultBuildHasher>;
|
||||||
pub(crate) type HashSet<T, H = DefaultBuildHasher> = hashbrown::HashSet<T, H>;
|
pub(crate) type HashSet<T> = hashbrown::HashSet<T, DefaultBuildHasher>;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
|
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
|
||||||
|
|
@ -43,11 +43,7 @@ pub use misc::{
|
||||||
};
|
};
|
||||||
pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice};
|
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 job_server;
|
||||||
pub mod map_trait;
|
|
||||||
pub mod prefix_sum;
|
pub mod prefix_sum;
|
||||||
pub mod ready_valid;
|
pub mod ready_valid;
|
||||||
pub(crate) mod serde_by_id;
|
pub(crate) mod serde_by_id;
|
||||||
pub mod union_find_map;
|
|
||||||
|
|
|
||||||
|
|
@ -1,711 +0,0 @@
|
||||||
// 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<usize>,
|
|
||||||
variables_value: Vec<bool>,
|
|
||||||
maximally_constrained: Vec<bool>,
|
|
||||||
unconstrained_variables_value: bool,
|
|
||||||
solved: bool,
|
|
||||||
and_constraints: BTreeSet<AndConstraint>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<AndConstraint>> =
|
|
||||||
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<Variable> = (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<Item = Constraint>> 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<Constraint>, Vec<Variable>, [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<Constraint>, Vec<Variable>, [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<Constraint>, Vec<Variable>, Vec<bool>> {
|
|
||||||
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<Constraint>, Vec<Variable>, Vec<bool>> {
|
|
||||||
#[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<Constraint>, Vec<Variable>, 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<I: IntoIterator<Item = Constraint>>(
|
|
||||||
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>) -> 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>) -> 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<u32> = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
// 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<IndentState> = 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<const LN: bool>(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::<false>($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::<true>($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;
|
|
||||||
|
|
@ -1,463 +0,0 @@
|
||||||
// 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<F: FnOnce(&mut M::Value)>(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<F: FnOnce() -> 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<F: FnOnce(&M::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<OccupiedEntry<'a>: 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<VacantEntry<'a> = Self> + 'a;
|
|
||||||
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value;
|
|
||||||
fn insert_entry(self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::OccupiedEntry<'a>;
|
|
||||||
fn into_key(self) -> <Self::Map as Map>::Key;
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait OccupiedEntry<'a>: Sized {
|
|
||||||
type Map: Map<OccupiedEntry<'a> = Self> + 'a;
|
|
||||||
fn get(&self) -> &<Self::Map as Map>::Value;
|
|
||||||
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value;
|
|
||||||
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value;
|
|
||||||
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value;
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::Key;
|
|
||||||
fn remove(self) -> <Self::Map as Map>::Value;
|
|
||||||
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Map:
|
|
||||||
Sized
|
|
||||||
+ IntoIterator<Item = (<Self as Map>::Key, <Self as Map>::Value)>
|
|
||||||
+ Extend<(<Self as Map>::Key, <Self as Map>::Value)>
|
|
||||||
+ FromIterator<(<Self as Map>::Key, <Self as Map>::Value)>
|
|
||||||
{
|
|
||||||
type Key;
|
|
||||||
type Value;
|
|
||||||
type IntoKeys: Iterator<Item = Self::Key>;
|
|
||||||
type IntoValues: Iterator<Item = Self::Value>;
|
|
||||||
type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
Self::Key: 'a,
|
|
||||||
Self::Value: 'a;
|
|
||||||
type IterMut<'a>: Iterator<Item = (&'a Self::Key, &'a mut Self::Value)>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
Self::Key: 'a,
|
|
||||||
Self::Value: 'a;
|
|
||||||
type Keys<'a>: Iterator<Item = &'a Self::Key>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
Self::Key: 'a;
|
|
||||||
type Values<'a>: Iterator<Item = &'a Self::Value>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
Self::Value: 'a;
|
|
||||||
type ValuesMut<'a>: Iterator<Item = &'a mut Self::Value>
|
|
||||||
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<Self::Value>;
|
|
||||||
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<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F);
|
|
||||||
fn values(&self) -> Self::Values<'_>;
|
|
||||||
fn values_mut(&mut self) -> Self::ValuesMut<'_>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MapGet<Q: ?Sized>: 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<Self::Value>;
|
|
||||||
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<K: Eq + Hash, V, H: BuildHasher + Default> Map for HashMap<K, V, H> {
|
|
||||||
type Key = K;
|
|
||||||
type Value = V;
|
|
||||||
type IntoKeys = hash_map::IntoKeys<K, V>;
|
|
||||||
type IntoValues = hash_map::IntoValues<K, V>;
|
|
||||||
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::Value> {
|
|
||||||
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<F: FnMut(&Self::Key, &mut Self::Value) -> 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<K: Eq + Hash, V, H: BuildHasher + Default, Q: ?Sized + Hash + Equivalent<K>> MapGet<Q>
|
|
||||||
for HashMap<K, V, H>
|
|
||||||
{
|
|
||||||
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::Value> {
|
|
||||||
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<K, V, H>;
|
|
||||||
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
|
|
||||||
self.insert(v)
|
|
||||||
}
|
|
||||||
fn insert_entry(
|
|
||||||
self,
|
|
||||||
v: <Self::Map as Map>::Value,
|
|
||||||
) -> <Self::Map as Map>::OccupiedEntry<'a> {
|
|
||||||
self.insert_entry(v)
|
|
||||||
}
|
|
||||||
fn into_key(self) -> <Self::Map as Map>::Key {
|
|
||||||
self.into_key()
|
|
||||||
}
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::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<K, V, H>;
|
|
||||||
fn get(&self) -> &<Self::Map as Map>::Value {
|
|
||||||
self.get()
|
|
||||||
}
|
|
||||||
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
|
|
||||||
self.get_mut()
|
|
||||||
}
|
|
||||||
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
|
|
||||||
self.insert(v)
|
|
||||||
}
|
|
||||||
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
|
|
||||||
self.into_mut()
|
|
||||||
}
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::Key {
|
|
||||||
self.key()
|
|
||||||
}
|
|
||||||
fn remove(self) -> <Self::Map as Map>::Value {
|
|
||||||
self.remove()
|
|
||||||
}
|
|
||||||
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
|
|
||||||
self.remove_entry()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod btree_map {
|
|
||||||
use super::*;
|
|
||||||
use std::collections::{BTreeMap, btree_map};
|
|
||||||
|
|
||||||
impl<K: Ord, V> Map for BTreeMap<K, V> {
|
|
||||||
type Key = K;
|
|
||||||
type Value = V;
|
|
||||||
type IntoKeys = btree_map::IntoKeys<K, V>;
|
|
||||||
type IntoValues = btree_map::IntoValues<K, V>;
|
|
||||||
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::Value> {
|
|
||||||
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<F: FnMut(&Self::Key, &mut Self::Value) -> 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<K: Ord + std::borrow::Borrow<Q>, V, Q: ?Sized + Ord> MapGet<Q> for BTreeMap<K, V> {
|
|
||||||
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::Value> {
|
|
||||||
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<K, V>;
|
|
||||||
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
|
|
||||||
self.insert(v)
|
|
||||||
}
|
|
||||||
fn insert_entry(
|
|
||||||
self,
|
|
||||||
v: <Self::Map as Map>::Value,
|
|
||||||
) -> <Self::Map as Map>::OccupiedEntry<'a> {
|
|
||||||
self.insert_entry(v)
|
|
||||||
}
|
|
||||||
fn into_key(self) -> <Self::Map as Map>::Key {
|
|
||||||
self.into_key()
|
|
||||||
}
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::Key {
|
|
||||||
self.key()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, K: Ord, V> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> {
|
|
||||||
type Map = BTreeMap<K, V>;
|
|
||||||
fn get(&self) -> &<Self::Map as Map>::Value {
|
|
||||||
self.get()
|
|
||||||
}
|
|
||||||
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
|
|
||||||
self.get_mut()
|
|
||||||
}
|
|
||||||
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
|
|
||||||
self.insert(v)
|
|
||||||
}
|
|
||||||
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
|
|
||||||
self.into_mut()
|
|
||||||
}
|
|
||||||
fn key(&self) -> &<Self::Map as Map>::Key {
|
|
||||||
self.key()
|
|
||||||
}
|
|
||||||
fn remove(self) -> <Self::Map as Map>::Value {
|
|
||||||
self.remove()
|
|
||||||
}
|
|
||||||
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
|
|
||||||
self.remove_entry()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,352 +0,0 @@
|
||||||
// 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<K, V, M = HashMap<K, usize>> {
|
|
||||||
uf: UnionFind<usize>,
|
|
||||||
keys_to_indexes: M,
|
|
||||||
values: Vec<Option<V>>,
|
|
||||||
_phantom: PhantomData<K>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K: fmt::Debug, V: fmt::Debug, M: Map<Key = K, Value = usize>> fmt::Debug
|
|
||||||
for UnionFindMap<K, V, M>
|
|
||||||
{
|
|
||||||
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("<<there's a misbehaving key>>")
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
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<K, V, M: Map<Key = K, Value = usize>> UnionFindMap<K, V, M> {
|
|
||||||
/// 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<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> bool
|
|
||||||
where
|
|
||||||
M: MapGet<K1> + MapGet<K2>,
|
|
||||||
{
|
|
||||||
self.try_equiv(k1, k2).expect("key not found")
|
|
||||||
}
|
|
||||||
pub fn try_equiv<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> Option<bool>
|
|
||||||
where
|
|
||||||
M: MapGet<K1> + MapGet<K2>,
|
|
||||||
{
|
|
||||||
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<Q: ?Sized>(&self, k: &Q) -> &V
|
|
||||||
where
|
|
||||||
M: MapGet<Q>,
|
|
||||||
{
|
|
||||||
self.try_find(k).expect("key not found")
|
|
||||||
}
|
|
||||||
pub fn try_find<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
|
||||||
where
|
|
||||||
M: MapGet<Q>,
|
|
||||||
{
|
|
||||||
let &index = self.keys_to_indexes.get(k)?;
|
|
||||||
self.values[self.uf.find(index)].as_ref()
|
|
||||||
}
|
|
||||||
#[track_caller]
|
|
||||||
pub fn find_mut<Q: ?Sized>(&mut self, k: &Q) -> &mut V
|
|
||||||
where
|
|
||||||
M: MapGet<Q>,
|
|
||||||
{
|
|
||||||
self.try_find_mut(k).expect("key not found")
|
|
||||||
}
|
|
||||||
pub fn try_find_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
|
||||||
where
|
|
||||||
M: MapGet<Q>,
|
|
||||||
{
|
|
||||||
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<V> {
|
|
||||||
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<K1: ?Sized, K2: ?Sized, F>(
|
|
||||||
&mut self,
|
|
||||||
k1: &K1,
|
|
||||||
k2: &K2,
|
|
||||||
merge: F,
|
|
||||||
) -> Option<(bool, &mut V)>
|
|
||||||
where
|
|
||||||
M: MapGet<K1> + MapGet<K2>,
|
|
||||||
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<K1: ?Sized, K2: ?Sized, F>(&mut self, k1: &K1, k2: &K2, merge: F) -> (bool, &mut V)
|
|
||||||
where
|
|
||||||
M: MapGet<K1> + MapGet<K2>,
|
|
||||||
F: FnOnce(&K1, V, &K2, V) -> V,
|
|
||||||
{
|
|
||||||
self.try_union(k1, k2, merge).expect("key not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V> UnionFindMap<K, V> {
|
|
||||||
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<K, V> UnionFindMap<K, V, BTreeMap<K, usize>> {
|
|
||||||
pub const fn new_btree() -> Self {
|
|
||||||
Self {
|
|
||||||
uf: UnionFind::new_empty(),
|
|
||||||
keys_to_indexes: BTreeMap::new(),
|
|
||||||
values: Vec::new(),
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K, V, H> UnionFindMap<K, V, HashMap<K, usize, H>> {
|
|
||||||
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<K, V, M: Default> Default for UnionFindMap<K, V, M> {
|
|
||||||
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<Key = K, Value = usize> + 'a> {
|
|
||||||
keys_to_indexes_entry: M::OccupiedEntry<'a>,
|
|
||||||
set_index: usize,
|
|
||||||
values: &'a mut [Option<V>],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, K, V, M: Map<Key = K, Value = usize> + '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<Key = K, Value = usize> + 'a> {
|
|
||||||
keys_to_indexes_entry: M::VacantEntry<'a>,
|
|
||||||
uf: &'a mut UnionFind<usize>,
|
|
||||||
values: &'a mut Vec<Option<V>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, K, V, M: Map<Key = K, Value = usize> + '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<Key = K, Value = usize> + 'a> {
|
|
||||||
Vacant(VacantEntry<'a, K, V, M>),
|
|
||||||
Occupied(OccupiedEntry<'a, K, V, M>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> Entry<'a, K, V, M> {
|
|
||||||
pub fn and_modify<F: FnOnce(&mut V)>(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<F: FnOnce() -> 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<F: FnOnce(&K) -> 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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -709,35 +709,44 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire _cast_enum_to_bits_expr: UInt<10>
|
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||||
match lhs:
|
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
match lhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
A:
|
A:
|
||||||
connect _cast_enum_to_bits_expr, UInt<10>(0)
|
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
B(_cast_enum_to_bits_expr_B):
|
A:
|
||||||
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
|
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
C(_cast_enum_to_bits_expr_C):
|
B(_match_arm_value):
|
||||||
wire _cast_array_to_bits_expr: UInt<1>[3]
|
skip
|
||||||
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
|
C(_match_arm_value_1):
|
||||||
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
|
skip
|
||||||
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
|
B(_match_arm_value_2):
|
||||||
wire _cast_to_bits_expr: UInt<3>
|
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
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]))
|
A:
|
||||||
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
|
skip
|
||||||
wire _cast_enum_to_bits_expr_1: UInt<10>
|
B(_match_arm_value_3):
|
||||||
match rhs:
|
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
A:
|
C(_match_arm_value_4):
|
||||||
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
|
skip
|
||||||
B(_cast_enum_to_bits_expr_B_1):
|
C(_match_arm_value_5):
|
||||||
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
|
match rhs: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
C(_cast_enum_to_bits_expr_C_1):
|
A:
|
||||||
wire _cast_array_to_bits_expr_1: UInt<1>[3]
|
skip
|
||||||
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
|
B(_match_arm_value_6):
|
||||||
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
|
skip
|
||||||
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
|
C(_match_arm_value_7):
|
||||||
wire _cast_to_bits_expr_1: UInt<3>
|
wire _array_literal_expr: UInt<1>[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 _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
|
||||||
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
|
connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
|
||||||
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5: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]
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
|
@ -755,53 +764,60 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
match lhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
wire _cast_enum_to_bits_expr: UInt<2>
|
|
||||||
match lhs.tag:
|
|
||||||
A:
|
A:
|
||||||
connect _cast_enum_to_bits_expr, UInt<2>(0)
|
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
|
||||||
B:
|
B:
|
||||||
connect _cast_enum_to_bits_expr, UInt<2>(1)
|
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
|
||||||
C:
|
C:
|
||||||
connect _cast_enum_to_bits_expr, UInt<2>(2)
|
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
|
||||||
wire _cast_enum_to_bits_expr_1: UInt<2>
|
A:
|
||||||
match rhs.tag:
|
skip
|
||||||
A:
|
B:
|
||||||
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
|
skip
|
||||||
B:
|
C:
|
||||||
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
|
wire _array_literal_expr: UInt<1>[3]
|
||||||
C:
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
A:
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
B:
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
C:
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
||||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
||||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1])
|
||||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2])
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
|
||||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
wire _cast_to_bits_expr: UInt<3>
|
||||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
|
||||||
wire _array_structural_eq: UInt<1>
|
connect TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5: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]))
|
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
|
||||||
wire _array_structural_eq_1: UInt<1>
|
|
||||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
|
||||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
|
@ -818,36 +834,51 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
|
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
skip
|
||||||
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
|
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
else:
|
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
skip
|
||||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
skip
|
||||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
skip
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
else:
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
wire _array_literal_expr: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
|
||||||
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
|
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
|
||||||
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
|
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
||||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
|
||||||
wire _array_structural_eq: UInt<1>
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _array_structural_eq_1: UInt<1>
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
|
||||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
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]
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
|
@ -863,36 +894,51 @@ circuit check_enum_cmp_eq:
|
||||||
input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
|
input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
|
||||||
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
|
||||||
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
|
||||||
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
|
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
|
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
|
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
|
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
|
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
|
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
|
skip
|
||||||
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 when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
else:
|
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
wire _cast_bits_to_array_expr: UInt<1>[3]
|
skip
|
||||||
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
|
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
|
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
|
skip
|
||||||
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
|
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
skip
|
||||||
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
else:
|
||||||
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
wire _array_literal_expr: UInt<1>[3]
|
||||||
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
wire _cast_bits_to_array_expr: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
|
||||||
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
|
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 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[0], _cast_bits_to_array_expr_flattened[0]
|
||||||
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
|
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 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], _cast_bits_to_array_expr_flattened[1]
|
||||||
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
|
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
|
||||||
wire _array_structural_eq: UInt<1>
|
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
|
||||||
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
|
wire _cast_bits_to_array_expr_1: UInt<1>[3]
|
||||||
wire _array_structural_eq_1: UInt<1>
|
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
|
||||||
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
|
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
|
||||||
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
|
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]
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -4863,20 +4909,34 @@ circuit check_struct_cmp_eq:
|
||||||
input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1]
|
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_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1]
|
||||||
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
|
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
|
||||||
wire _bundle_structural_eq: UInt<1>
|
wire _array_literal_expr: UInt<1>[3]
|
||||||
connect _bundle_structural_eq, and(eq(tuple_lhs.`0`, tuple_rhs.`0`), eq(tuple_lhs.`1`, tuple_rhs.`1`))
|
connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`)
|
||||||
wire _bundle_structural_eq_1: UInt<1>
|
connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`)
|
||||||
connect _bundle_structural_eq_1, and(_bundle_structural_eq, eq(tuple_lhs.`2`, tuple_rhs.`2`))
|
connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`)
|
||||||
connect tuple_cmp_eq, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 5:1]
|
wire _cast_array_to_bits_expr: UInt<1>[3]
|
||||||
connect tuple_cmp_ne, not(_bundle_structural_eq_1) @[module-XXXXXXXXXX.rs 7:1]
|
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
|
||||||
wire _bundle_structural_eq_2: UInt<1>
|
connect _cast_array_to_bits_expr[1], _array_literal_expr[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 _cast_array_to_bits_expr[2], _array_literal_expr[2]
|
||||||
connect test_struct_cmp_eq, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 11:1]
|
wire _cast_to_bits_expr: UInt<3>
|
||||||
connect test_struct_cmp_ne, not(_bundle_structural_eq_2) @[module-XXXXXXXXXX.rs 13:1]
|
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]
|
||||||
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
|
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
|
||||||
connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19: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_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
|
connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
|
||||||
connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1]
|
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3749,67 +3749,3 @@ 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<UInt<2>> = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let b: HdlOption<UInt<2>> = 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!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,522 +0,0 @@
|
||||||
Simulation {
|
|
||||||
state: State {
|
|
||||||
insns: Insns {
|
|
||||||
state_layout: StateLayout {
|
|
||||||
ty: TypeLayout {
|
|
||||||
small_slots: StatePartLayout<SmallSlots> {
|
|
||||||
len: 2,
|
|
||||||
debug_data: [
|
|
||||||
SlotDebugData {
|
|
||||||
name: "",
|
|
||||||
ty: Enum {
|
|
||||||
HdlNone,
|
|
||||||
HdlSome,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SlotDebugData {
|
|
||||||
name: "",
|
|
||||||
ty: Enum {
|
|
||||||
HdlNone,
|
|
||||||
HdlSome,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
..
|
|
||||||
},
|
|
||||||
big_slots: StatePartLayout<BigSlots> {
|
|
||||||
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<SimOnlySlots> {
|
|
||||||
len: 0,
|
|
||||||
debug_data: [],
|
|
||||||
layout_data: [],
|
|
||||||
..
|
|
||||||
},
|
|
||||||
},
|
|
||||||
memories: StatePartLayout<Memories> {
|
|
||||||
len: 0,
|
|
||||||
debug_data: [],
|
|
||||||
layout_data: [],
|
|
||||||
..
|
|
||||||
},
|
|
||||||
},
|
|
||||||
insns: [
|
|
||||||
// at: module-XXXXXXXXXX.rs:1:1
|
|
||||||
0: Const {
|
|
||||||
dest: StatePartIndex<BigSlots>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
value: 0x1,
|
|
||||||
},
|
|
||||||
1: Const {
|
|
||||||
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
value: 0x0,
|
|
||||||
},
|
|
||||||
2: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
src: StatePartIndex<BigSlots>(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<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
|
||||||
src: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
start: 1,
|
|
||||||
len: 2,
|
|
||||||
},
|
|
||||||
// at: module-XXXXXXXXXX.rs:3:1
|
|
||||||
4: AndBigWithSmallImmediate {
|
|
||||||
dest: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
lhs: StatePartIndex<BigSlots>(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<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
src: StatePartIndex<BigSlots>(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<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
|
||||||
src: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
start: 1,
|
|
||||||
len: 2,
|
|
||||||
},
|
|
||||||
7: CmpEq {
|
|
||||||
dest: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
lhs: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
|
||||||
rhs: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
|
|
||||||
},
|
|
||||||
8: CmpEq {
|
|
||||||
dest: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
lhs: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
rhs: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
|
|
||||||
},
|
|
||||||
// at: module-XXXXXXXXXX.rs:9:1
|
|
||||||
9: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(8), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", ty: Bool },
|
|
||||||
src: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
},
|
|
||||||
// at: module-XXXXXXXXXX.rs:2:1
|
|
||||||
10: AndBigWithSmallImmediate {
|
|
||||||
dest: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
lhs: StatePartIndex<BigSlots>(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<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
rhs: 0x0,
|
|
||||||
},
|
|
||||||
12: BranchIfSmallNeImmediate {
|
|
||||||
target: 14,
|
|
||||||
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
rhs: 0x0,
|
|
||||||
},
|
|
||||||
13: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
src: StatePartIndex<BigSlots>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
},
|
|
||||||
14: BranchIfSmallNeImmediate {
|
|
||||||
target: 17,
|
|
||||||
lhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
rhs: 0x1,
|
|
||||||
},
|
|
||||||
15: BranchIfSmallNeImmediate {
|
|
||||||
target: 17,
|
|
||||||
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
|
|
||||||
rhs: 0x1,
|
|
||||||
},
|
|
||||||
16: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
src: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
},
|
|
||||||
// at: module-XXXXXXXXXX.rs:7:1
|
|
||||||
17: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(6), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", ty: Bool },
|
|
||||||
src: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
|
|
||||||
},
|
|
||||||
// at: module-XXXXXXXXXX.rs:8:1
|
|
||||||
18: Copy {
|
|
||||||
dest: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", ty: Bool },
|
|
||||||
src: StatePartIndex<BigSlots>(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: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
},
|
|
||||||
global_io: {},
|
|
||||||
main_module: SimulationModuleState {
|
|
||||||
base_targets: [
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.a,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.b,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.eq,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.structural_eq,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.bit_eq,
|
|
||||||
],
|
|
||||||
uninitialized_ios: {},
|
|
||||||
io_targets: {
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.a,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.b,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.bit_eq,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::enum_structural_eq,
|
|
||||||
instantiated: Module {
|
|
||||||
name: enum_structural_eq,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
}.eq,
|
|
||||||
Instance {
|
|
||||||
name: <simulator>::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<SmallSlots>(0),
|
|
||||||
ty: Enum {
|
|
||||||
HdlNone,
|
|
||||||
HdlSome(UInt<2>),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x1,
|
|
||||||
last_state: 0x1,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(1),
|
|
||||||
kind: BigUInt {
|
|
||||||
index: StatePartIndex<BigSlots>(2),
|
|
||||||
ty: UInt<2>,
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x3,
|
|
||||||
last_state: 0x3,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(2),
|
|
||||||
kind: EnumDiscriminant {
|
|
||||||
index: StatePartIndex<SmallSlots>(1),
|
|
||||||
ty: Enum {
|
|
||||||
HdlNone,
|
|
||||||
HdlSome(UInt<2>),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x1,
|
|
||||||
last_state: 0x0,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(3),
|
|
||||||
kind: BigUInt {
|
|
||||||
index: StatePartIndex<BigSlots>(5),
|
|
||||||
ty: UInt<2>,
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x3,
|
|
||||||
last_state: 0x3,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(4),
|
|
||||||
kind: BigBool {
|
|
||||||
index: StatePartIndex<BigSlots>(6),
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x1,
|
|
||||||
last_state: 0x0,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(5),
|
|
||||||
kind: BigBool {
|
|
||||||
index: StatePartIndex<BigSlots>(7),
|
|
||||||
},
|
|
||||||
maybe_changed: true,
|
|
||||||
state: 0x1,
|
|
||||||
last_state: 0x0,
|
|
||||||
},
|
|
||||||
SimTrace {
|
|
||||||
id: TraceScalarId(6),
|
|
||||||
kind: BigBool {
|
|
||||||
index: StatePartIndex<BigSlots>(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: [],
|
|
||||||
..
|
|
||||||
}
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
$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
|
|
||||||
|
|
@ -75,7 +75,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
929 | pub struct OpaqueSimValue {
|
896 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
@ -214,7 +214,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
929 | pub struct OpaqueSimValue {
|
896 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
@ -326,7 +326,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
|
||||||
note: required because it appears within the type `OpaqueSimValue`
|
note: required because it appears within the type `OpaqueSimValue`
|
||||||
--> src/ty.rs
|
--> src/ty.rs
|
||||||
|
|
|
|
||||||
929 | pub struct OpaqueSimValue {
|
896 | pub struct OpaqueSimValue {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
note: required because it appears within the type `value::SimValueInner<()>`
|
note: required because it appears within the type `value::SimValueInner<()>`
|
||||||
--> src/sim/value.rs
|
--> src/sim/value.rs
|
||||||
|
|
|
||||||
|
|
@ -1055,15 +1055,6 @@
|
||||||
"global()": "Visible"
|
"global()": "Visible"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ops::StructuralEq": {
|
|
||||||
"data": {
|
|
||||||
"$kind": "Struct",
|
|
||||||
"$constructor": "ops::StructuralEq::with_flags",
|
|
||||||
"lhs()": "Visible",
|
|
||||||
"rhs()": "Visible",
|
|
||||||
"flags()": "Opaque"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BlockId": {
|
"BlockId": {
|
||||||
"data": {
|
"data": {
|
||||||
"$kind": "Opaque"
|
"$kind": "Opaque"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue