diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 3309fb1..e235cd7 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -218,7 +218,7 @@ expr_enum! { SliceSInt(ops::SliceSInt), CastToBits(ops::CastToBits), CastBitsTo(ops::CastBitsTo), - AsTraceAsString(ops::AsTraceAsString), + ToTraceAsString(ops::ToTraceAsString), TraceAsStringAsInner(ops::TraceAsStringAsInner), ModuleIO(ModuleIO), Instance(Instance), @@ -394,7 +394,7 @@ impl Expr { #[track_caller] pub fn as_trace_as_string(this: Self, ty: TraceAsString) -> Expr> { assert_eq!(this.ty(), ty.inner_ty()); - ops::AsTraceAsString::new(Expr::canonical(this), ty).to_expr() + ops::ToTraceAsString::new(Expr::canonical(this), ty).to_expr() } } @@ -1723,3 +1723,188 @@ impl<'a, T: Type> ToSimValueInner<'a> for &'a SimValue { Cow::Borrowed(&**this) } } + +pub trait ToTraceAsString: ValueType { + type Output: ValueType, ValueCategory = Self::ValueCategory>; + fn to_trace_as_string_with_ty(&self, ty: TraceAsString) -> Self::Output; + fn into_trace_as_string_with_ty(self, ty: TraceAsString) -> Self::Output + where + Self: Sized; + fn to_trace_as_string(&self) -> Self::Output; + fn into_trace_as_string(self) -> Self::Output + where + Self: Sized; +} + +impl< + T: ?Sized + + ValueType + + ToTraceAsStringImpl<::Type, ::ValueCategory>, +> ToTraceAsString for T +{ + type Output = T::ImplOutput; + fn to_trace_as_string_with_ty(&self, ty: TraceAsString) -> Self::Output { + Self::to_trace_as_string_with_ty_impl(self, ty) + } + fn into_trace_as_string_with_ty(self, ty: TraceAsString) -> Self::Output + where + Self: Sized, + { + Self::into_trace_as_string_with_ty_impl(self, ty) + } + fn to_trace_as_string(&self) -> Self::Output { + Self::to_trace_as_string_impl(self) + } + fn into_trace_as_string(self) -> Self::Output + where + Self: Sized, + { + Self::into_trace_as_string_impl(self) + } +} + +pub trait ToTraceAsStringImpl { + type ImplOutput: ValueType, ValueCategory = C>; + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput; + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized; + fn to_trace_as_string_with_ty_impl(this: &Self, ty: TraceAsString) -> Self::ImplOutput; + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized; +} + +impl + ToTraceAsStringImpl for T +{ + type ImplOutput = crate::ty::TraceAsStringSimValue; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new(this) + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new(this) + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty) + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty) + } +} + +impl + ToTraceAsStringImpl for T +{ + type ImplOutput = SimValue>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new(this).into_sim_value() + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new(this).into_sim_value() + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value() + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value() + } +} + +impl ToTraceAsStringImpl for T { + type ImplOutput = Expr>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + let this = this.to_expr(); + ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr() + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + let this = this.to_expr(); + ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr() + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + let this = this.to_expr(); + ops::ToTraceAsString::new( + Expr::canonical(this), + ty.with_new_inner_ty(this.ty().intern_sized()), + ) + .to_expr() + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + let this = this.to_expr(); + ops::ToTraceAsString::new( + Expr::canonical(this), + ty.with_new_inner_ty(this.ty().intern_sized()), + ) + .to_expr() + } +} + +impl ToTraceAsStringImpl + for T +{ + type ImplOutput = Valueless>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + Valueless::new(TraceAsString::new(this.ty())) + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + Valueless::new(TraceAsString::new(this.ty())) + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized())) + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized())) + } +} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index 22a0d99..b2e20ad 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -11,8 +11,8 @@ use crate::{ HdlPartialEqImpl, HdlPartialOrd, HdlPartialOrdImpl, NotALiteralExpr, ReduceBitsImpl, ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless, target::{ - GetTarget, Target, TargetPathArrayElement, TargetPathAsTraceAsString, - TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, value_category::ValueCategoryExpr, @@ -45,6 +45,9 @@ use std::{ }, }; +#[cfg(test)] +mod test_ops_impls; + macro_rules! make_impls { ( $([$($args:tt)*])? @@ -584,9 +587,6 @@ macro_rules! make_impls { #[cfg(test)] pub(crate) use make_impls; -#[cfg(test)] -mod test_ops_impls; - macro_rules! impl_simple_binary_op_trait { ( [$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), @@ -4697,14 +4697,14 @@ impl, A> FromIterator for Expr { } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct AsTraceAsString { +pub struct ToTraceAsString { inner: Expr, ty: TraceAsString, literal_bits: Result, NotALiteralExpr>, target: Option>, } -impl fmt::Debug for AsTraceAsString { +impl fmt::Debug for ToTraceAsString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { inner, @@ -4712,24 +4712,25 @@ impl fmt::Debug for AsTraceAsString { literal_bits: _, target: _, } = self; - f.debug_struct("AsTraceAsString") + f.debug_struct("ToTraceAsString") .field("inner", inner) .finish_non_exhaustive() } } -impl AsTraceAsString { +impl ToTraceAsString { pub fn new(inner: Expr, ty: TraceAsString) -> Self { assert_eq!(inner.ty(), ty.inner_ty().canonical()); let literal_bits = inner.to_literal_bits(); let target = inner.target().map(|base| { Intern::intern_sized( base.join(TargetPathElement::intern_sized( - TargetPathAsTraceAsString { + TargetPathToTraceAsString { ty: ty.canonical_trace_as_string(), } .into(), - )), + )) + .canonicalized(), ) }); Self { @@ -4744,19 +4745,19 @@ impl AsTraceAsString { } } -impl GetTarget for AsTraceAsString { +impl GetTarget for ToTraceAsString { fn target(&self) -> Option> { self.target } } -impl ToLiteralBits for AsTraceAsString { +impl ToLiteralBits for ToTraceAsString { fn to_literal_bits(&self) -> Result, NotALiteralExpr> { self.literal_bits } } -impl ValueType for AsTraceAsString { +impl ValueType for ToTraceAsString { type Type = TraceAsString; type ValueCategory = ValueCategoryExpr; @@ -4765,10 +4766,10 @@ impl ValueType for AsTraceAsString { } } -impl ToExpr for AsTraceAsString { +impl ToExpr for ToTraceAsString { fn to_expr(&self) -> Expr { Expr { - __enum: ExprEnum::AsTraceAsString(AsTraceAsString { + __enum: ExprEnum::ToTraceAsString(ToTraceAsString { inner: self.inner, ty: self.ty.canonical_trace_as_string(), literal_bits: self.literal_bits, @@ -4808,9 +4809,12 @@ impl TraceAsStringAsInner { assert_eq!(arg.ty().inner_ty(), ty.canonical()); let literal_bits = arg.to_literal_bits(); let target = arg.target().map(|base| { - Intern::intern_sized(base.join(TargetPathElement::intern_sized( - TargetPathTraceAsStringInner {}.into(), - ))) + Intern::intern_sized( + base.join(TargetPathElement::intern_sized( + TargetPathTraceAsStringInner {}.into(), + )) + .canonicalized(), + ) }); Self { arg, diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index 5140719..9016111 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -56,13 +56,13 @@ impl fmt::Display for TargetPathTraceAsStringInner { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct TargetPathAsTraceAsString { +pub struct TargetPathToTraceAsString { pub ty: TraceAsString, } -impl fmt::Display for TargetPathAsTraceAsString { +impl fmt::Display for TargetPathToTraceAsString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, ".as_trace_as_string(...)") + write!(f, ".to_trace_as_string(...)") } } @@ -72,7 +72,7 @@ pub enum TargetPathElement { ArrayElement(TargetPathArrayElement), DynArrayElement(TargetPathDynArrayElement), TraceAsStringInner(TargetPathTraceAsStringInner), - AsTraceAsString(TargetPathAsTraceAsString), + ToTraceAsString(TargetPathToTraceAsString), } impl From for TargetPathElement { @@ -99,9 +99,9 @@ impl From for TargetPathElement { } } -impl From for TargetPathElement { - fn from(value: TargetPathAsTraceAsString) -> Self { - Self::AsTraceAsString(value) +impl From for TargetPathElement { + fn from(value: TargetPathToTraceAsString) -> Self { + Self::ToTraceAsString(value) } } @@ -112,7 +112,7 @@ impl fmt::Display for TargetPathElement { Self::ArrayElement(v) => v.fmt(f), Self::DynArrayElement(v) => v.fmt(f), Self::TraceAsStringInner(v) => v.fmt(f), - Self::AsTraceAsString(v) => v.fmt(f), + Self::ToTraceAsString(v) => v.fmt(f), } } } @@ -141,7 +141,7 @@ impl TargetPathElement { TraceAsString::::from_canonical(parent.canonical_ty()); parent_ty.inner_ty() } - &Self::AsTraceAsString(TargetPathAsTraceAsString { ty }) => { + &Self::ToTraceAsString(TargetPathToTraceAsString { ty }) => { assert_eq!(parent.canonical_ty(), ty.inner_ty()); ty.canonical() } @@ -159,7 +159,7 @@ impl TargetPathElement { Self::ArrayElement(_) | Self::DynArrayElement(_) | Self::TraceAsStringInner(_) - | Self::AsTraceAsString(_) => parent.flow(), + | Self::ToTraceAsString(_) => parent.flow(), } } pub fn is_static(&self) -> bool { @@ -167,7 +167,7 @@ impl TargetPathElement { Self::BundleField(_) | Self::ArrayElement(_) | Self::TraceAsStringInner(_) - | Self::AsTraceAsString(_) => true, + | Self::ToTraceAsString(_) => true, Self::DynArrayElement(_) => false, } } @@ -364,6 +364,7 @@ pub struct TargetChild { path_element: Interned, canonical_ty: CanonicalType, flow: Flow, + canonicalized_if_different: Option>, } impl fmt::Debug for TargetChild { @@ -373,6 +374,7 @@ impl fmt::Debug for TargetChild { path_element, canonical_ty: _, flow: _, + canonicalized_if_different: _, } = self; parent.fmt(f)?; fmt::Display::fmt(path_element, f) @@ -386,6 +388,7 @@ impl fmt::Display for TargetChild { path_element, canonical_ty: _, flow: _, + canonicalized_if_different: _, } = self; parent.fmt(f)?; path_element.fmt(f) @@ -393,14 +396,69 @@ impl fmt::Display for TargetChild { } impl TargetChild { - pub fn new(parent: Interned, path_element: Interned) -> Self { + fn new_helper( + parent: Interned, + path_element: Interned, + canonicalized_if_different: Option>, + ) -> Self { Self { parent, path_element, canonical_ty: path_element.canonical_ty(parent), flow: path_element.flow(parent), + canonicalized_if_different, } } + fn make_canonicalized_if_different( + parent: Interned, + path_element: Interned, + ) -> Option> { + use TargetPathElement::*; + match *path_element { + BundleField(_) => {} + ArrayElement(_) => {} + DynArrayElement(_) => {} + TraceAsStringInner(_) => { + if let Some(child) = parent.canonicalized().child() { + match *child.path_element() { + BundleField(_) + | ArrayElement(_) + | DynArrayElement(_) + | TraceAsStringInner(_) => {} + ToTraceAsString(_) => return Some(child.parent()), + } + } + } + ToTraceAsString(TargetPathToTraceAsString { ty }) => { + if let Some(child) = parent.canonicalized().child() { + match *child.path_element() { + BundleField(_) | ArrayElement(_) | DynArrayElement(_) + | ToTraceAsString(_) => {} + TraceAsStringInner(_) => { + if ty.canonical() == child.parent().canonical_ty() { + return Some(child.parent()); + } + } + } + } + } + } + Some( + Target::Child(Self::new_helper( + parent.canonicalized_if_different()?, + path_element, + None, + )) + .intern_sized(), + ) + } + pub fn new(parent: Interned, path_element: Interned) -> Self { + Self::new_helper( + parent, + path_element, + Self::make_canonicalized_if_different(parent, path_element), + ) + } pub fn parent(self) -> Interned { self.parent } @@ -413,6 +471,19 @@ impl TargetChild { pub fn flow(self) -> Flow { self.flow } + pub fn is_canonicalized(self) -> bool { + self.canonicalized_if_different.is_none() + } + pub fn canonicalized_if_different(self) -> Option> { + self.canonicalized_if_different + } + #[must_use] + pub fn canonicalized(self) -> Target { + match self.canonicalized_if_different { + Some(v) => *v, + None => Target::Child(self), + } + } pub fn bundle_field(self) -> Option { if let TargetPathElement::BundleField(TargetPathBundleField { name }) = *self.path_element { let parent_ty = Bundle::from_canonical(self.parent.canonical_ty()); @@ -493,6 +564,82 @@ impl Target { Target::Child(v) => v.canonical_ty(), } } + pub fn is_canonicalized(self) -> bool { + match self { + Self::Base(_) => true, + Self::Child(child) => child.is_canonicalized(), + } + } + pub fn canonicalized_if_different(self) -> Option> { + match self { + Self::Base(_) => None, + Self::Child(child) => child.canonicalized_if_different(), + } + } + #[must_use] + pub fn canonicalized(self) -> Target { + match self.canonicalized_if_different() { + Some(v) => *v, + None => self, + } + } + #[must_use] + pub fn canonicalized_interned(this: Interned) -> Interned { + this.canonicalized_if_different().unwrap_or(this) + } + #[must_use] + pub fn unwrap_transparent_types(mut self) -> Target { + loop { + self = self.canonicalized(); + match self.canonical_ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => return self, + CanonicalType::TraceAsString(_) => { + if let Self::Child(child) = self + && let TargetPathElement::ToTraceAsString(_) = *child.path_element() + { + self = *child.parent(); + } else { + self = self.join(TargetPathElement::intern_sized( + TargetPathTraceAsStringInner {}.into(), + )); + } + } + } + } + } + #[must_use] + pub fn unwrap_transparent_types_interned(this: Interned) -> Interned { + let retval = this.unwrap_transparent_types(); + if retval != *this { + retval.intern_sized() + } else { + this + } + } + #[must_use] + pub fn without_trailing_transparent_path_elements(mut self) -> Target { + use TargetPathElement::*; + loop { + match self { + Self::Base(_) => return self, + Self::Child(child) => match *child.path_element() { + BundleField(_) | ArrayElement(_) | DynArrayElement(_) => return self, + TraceAsStringInner(_) | ToTraceAsString(_) => self = *child.parent(), + }, + } + } + } } impl fmt::Display for Target { diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 23aeb2e..51aa040 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -1802,7 +1802,7 @@ impl<'a> Exporter<'a> { write!(out, "[{index}]").unwrap(); Ok(out) } - ExprEnum::AsTraceAsString(expr) => self.expr(expr.inner(), definitions, const_ty), + ExprEnum::ToTraceAsString(expr) => self.expr(expr.inner(), definitions, const_ty), ExprEnum::TraceAsStringAsInner(expr) => { self.expr(Expr::canonical(expr.arg()), definitions, const_ty) } @@ -1965,7 +1965,7 @@ impl<'a> Exporter<'a> { .segments .push(AnnotationTargetRefSegment::Index { index }), TargetPathElement::DynArrayElement(_) => unreachable!(), - TargetPathElement::AsTraceAsString(_) + TargetPathElement::ToTraceAsString(_) | TargetPathElement::TraceAsStringInner(_) => { // ignored } @@ -3223,7 +3223,7 @@ impl ScalarizeTreeNode { TargetPathElement::DynArrayElement(_) => { unreachable!("annotations are only on static targets"); } - TargetPathElement::AsTraceAsString(_) + TargetPathElement::ToTraceAsString(_) | TargetPathElement::TraceAsStringInner(_) => parent, } } diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index f39f800..816a286 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -12,7 +12,7 @@ use crate::{ ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, TargetPathTraceAsStringInner, + TargetPathElement, }, value_category::ValueCategoryExpr, }, @@ -1113,7 +1113,7 @@ fn validate_clock_for_past( match *child.path_element() { TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) - | TargetPathElement::AsTraceAsString(_) + | TargetPathElement::ToTraceAsString(_) | TargetPathElement::TraceAsStringInner(_) => {} TargetPathElement::DynArrayElement(_) => { panic!( @@ -1538,6 +1538,7 @@ impl TargetState { } } fn new(target: Interned, declared_in_block: usize) -> Self { + let target = Target::unwrap_transparent_types_interned(target); Self { target, inner: match target.canonical_ty() { @@ -1590,12 +1591,7 @@ impl TargetState { written_in_blocks: RefCell::default(), }, CanonicalType::TraceAsString(_) => { - return Self::new( - target - .join(Intern::intern_sized(TargetPathTraceAsStringInner {}.into())) - .intern_sized(), - declared_in_block, - ); + unreachable!("handled by Target::unwrap_transparent_types_interned") } }, } @@ -1616,13 +1612,14 @@ impl AssertValidityState { } fn get_target_states<'a>( &'a self, - mut target: &Target, + target: Target, process_target_state: &dyn Fn(&'a TargetState, bool), ) -> Result<(), ()> { + let mut target = target.unwrap_transparent_types(); loop { break match target { Target::Base(target_base) => { - let target_state = self.get_base_state(*target_base)?; + let target_state = self.get_base_state(target_base)?; process_target_state(target_state, false); Ok(()) } @@ -1630,7 +1627,7 @@ impl AssertValidityState { TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) | TargetPathElement::DynArrayElement(_) => self.get_target_states( - &target_child.parent(), + *target_child.parent(), &|target_state, exact_target_unknown| { let TargetStateInner::Decomposed { subtargets } = &target_state.inner else { @@ -1657,13 +1654,13 @@ impl AssertValidityState { } } TargetPathElement::TraceAsStringInner(_) - | TargetPathElement::AsTraceAsString(_) => unreachable!(), + | TargetPathElement::ToTraceAsString(_) => unreachable!(), } }, ), TargetPathElement::TraceAsStringInner(_) - | TargetPathElement::AsTraceAsString(_) => { - target = Interned::into_inner(target_child.parent()); + | TargetPathElement::ToTraceAsString(_) => { + target = *target_child.parent(); continue; } }, @@ -1718,6 +1715,7 @@ impl AssertValidityState { &TargetPathElement::BundleField(_) => { let field = sub_target_state .target + .without_trailing_transparent_path_elements() .child() .expect("known to be a child") .bundle_field() @@ -1742,7 +1740,7 @@ impl AssertValidityState { Self::set_connect_target_written(sub_target_state, is_lhs, block, true); } TargetPathElement::TraceAsStringInner(_) - | TargetPathElement::AsTraceAsString(_) => unreachable!("never added"), + | TargetPathElement::ToTraceAsString(_) => unreachable!("never added"), } } } @@ -1760,7 +1758,7 @@ impl AssertValidityState { debug_assert!(!is_lhs, "the ModuleBuilder asserts lhs.target().is_some()"); return; }; - let result = self.get_target_states(&target, &|target_state, exact_target_unknown| { + let result = self.get_target_states(*target, &|target_state, exact_target_unknown| { Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown); }); if result.is_err() { diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index ef95c1c..4595e84 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -9,8 +9,8 @@ use crate::{ ExprEnum, ValueType, ops::{self, ArrayLiteral}, target::{ - Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathAsTraceAsString, - TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, }, @@ -1207,7 +1207,7 @@ impl RunPass

for ExprEnum { ExprEnum::TraceAsStringAsInner(expr) => { Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) } - ExprEnum::AsTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1617,7 +1617,7 @@ impl RunPassExpr for ops::TraceAsStringAsInner { } } -impl RunPassExpr for ops::AsTraceAsString { +impl RunPassExpr for ops::ToTraceAsString { type Args<'a> = [Expr; 1]; fn args<'a>(&'a self) -> Self::Args<'a> { @@ -2307,8 +2307,8 @@ impl RunPass

for TargetChild { | TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => { self.path_element() } - TargetPathElement::AsTraceAsString(TargetPathAsTraceAsString { ty }) => { - TargetPathElement::from(TargetPathAsTraceAsString { + TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => { + TargetPathElement::from(TargetPathToTraceAsString { ty: ty.with_new_inner_ty(parent.canonical_ty().intern_sized()), }) .intern_sized() diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index 02b4dda..5f136f2 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -807,7 +807,7 @@ impl Folder for State { | ExprEnum::CastToBits(_) | ExprEnum::CastBitsTo(_) | ExprEnum::TraceAsStringAsInner(_) - | ExprEnum::AsTraceAsString(_) + | ExprEnum::ToTraceAsString(_) | ExprEnum::ModuleIO(_) | ExprEnum::Instance(_) | ExprEnum::Wire(_) diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 134d9a8..7b4cd2a 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -13,8 +13,8 @@ use crate::{ expr::{ Expr, ExprEnum, ValueType, ops, target::{ - Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathAsTraceAsString, - TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, }, diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 4c5bfdf..42038ca 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -13,7 +13,7 @@ pub use crate::{ enum_::{Enum, HdlNone, HdlOption, HdlSome}, expr::{ CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, - ReduceBits, ToExpr, ValueType, repeat, + ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat, }, formal::{ MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, @@ -38,7 +38,7 @@ pub use crate::{ }, source_location::SourceLocation, testing::{FormalMode, assert_formal}, - ty::{AsMask, CanonicalType, Type}, + ty::{AsMask, CanonicalType, TraceAsString, Type}, util::{ConstUsize, GenericConstUsize}, wire::Wire, }; diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 658ae10..1247fd8 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -1307,7 +1307,7 @@ impl SimulationModuleState { TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) | TargetPathElement::TraceAsStringInner(_) - | TargetPathElement::AsTraceAsString(_) => {} + | TargetPathElement::ToTraceAsString(_) => {} TargetPathElement::DynArrayElement(_) => panic!( "simulator read/write expression must not have dynamic array indexes" ), diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index 4f5c571..4d6d9bc 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -9,8 +9,8 @@ use crate::{ expr::{ ExprEnum, Flow, ValueType, ops, target::{ - GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathAsTraceAsString, - TargetPathBundleField, TargetPathElement, TargetPathTraceAsStringInner, + GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, + TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, }, int::BoolOrIntType, @@ -2686,7 +2686,7 @@ impl Compiler { TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => { parent.map_ty(TraceAsString::from_canonical).inner() } - TargetPathElement::AsTraceAsString(TargetPathAsTraceAsString { ty }) => parent + TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => parent .wrap_in_trace_as_string(ty) .map_ty(|ty| ty.canonical()), } @@ -3017,7 +3017,7 @@ impl Compiler { }); } CanonicalType::TraceAsString(ty) => Expr::canonical( - ops::AsTraceAsString::new( + ops::ToTraceAsString::new( match arg { Some(arg) => arg.cast_bits_to(ty.inner_ty()), None => ty.inner_ty().uninit(), @@ -3838,7 +3838,7 @@ impl Compiler { ExprEnum::CastBitsTo(expr) => self .compile_cast_bits_to_or_uninit(instantiated_module, Some(expr.arg()), expr.ty()) .into(), - ExprEnum::AsTraceAsString(expr) => self + ExprEnum::ToTraceAsString(expr) => self .compile_expr(instantiated_module, expr.inner()) .wrap_in_trace_as_string(expr.ty()) .map_ty(|ty| ty.canonical()), diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index 79515ac..24bc1ef 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -19,20 +19,19 @@ use crate::{ impl_match_variant_as_self, }, util::{ - ConstUsize, HashMap, + ConstUsize, alternating_cell::{AlternatingCell, AlternatingCellMethods}, + serde_by_id::{SerdeById, SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait}, }, }; use bitvec::{slice::BitSlice, vec::BitVec}; -use hashbrown::hash_map::Entry; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _}; use std::{ borrow::{Borrow, BorrowMut, Cow}, - fmt::{self, Write}, - hash::{BuildHasher, Hash, Hasher, RandomState}, + fmt, num::NonZero, ops::{Deref, DerefMut, Index, IndexMut}, - sync::{Arc, Mutex}, + sync::Arc, }; pub(crate) mod sim_only_value_unsafe; @@ -1228,80 +1227,17 @@ macro_rules! impl_to_sim_value_for_int_value { impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); -#[derive(Default)] -struct DynSimOnlySerdeTableRest { - from_serde: HashMap, - serde_id_random_state: RandomState, - buffer: String, -} - -impl DynSimOnlySerdeTableRest { - #[cold] - fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId { - let mut try_number = 0u64; - let mut hasher = self.serde_id_random_state.build_hasher(); - // extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits - write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail"); - self.buffer.hash(&mut hasher); - loop { - let mut hasher = hasher.clone(); - try_number.hash(&mut hasher); - try_number += 1; - let retval = DynSimOnlySerdeId(std::array::from_fn(|i| { - let mut hasher = hasher.clone(); - i.hash(&mut hasher); - hasher.finish() as u32 - })); - match self.from_serde.entry(retval) { - Entry::Occupied(_) => continue, - Entry::Vacant(e) => { - e.insert(ty); - return retval; - } - } - } +impl SerdeByIdTrait for DynSimOnly { + fn serde_by_id_properties(&self) -> SerdeByIdProperties { + self.serde_by_id_properties_inner() } -} -#[derive(Default)] -struct DynSimOnlySerdeTable { - to_serde: HashMap, - rest: DynSimOnlySerdeTableRest, -} - -static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex> = Mutex::new(None); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] -#[serde(transparent)] -struct DynSimOnlySerdeId([u32; 4]); - -impl From for DynSimOnlySerdeId { - fn from(ty: DynSimOnly) -> Self { - let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE - .lock() - .expect("shouldn't be poison"); - let DynSimOnlySerdeTable { to_serde, rest } = locked.get_or_insert_default(); - match to_serde.entry(ty) { - Entry::Occupied(occupied_entry) => *occupied_entry.get(), - Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)), - } + fn static_table() -> &'static SerdeByIdTable { + static TABLE: SerdeByIdTable = SerdeByIdTable::new(); + &TABLE } -} -impl DynSimOnlySerdeId { - fn ty(self) -> Option { - let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE - .lock() - .expect("shouldn't be poison"); - Some(*locked.as_ref()?.rest.from_serde.get(&self)?) - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] -struct DynSimOnlySerde<'a> { - random_id: DynSimOnlySerdeId, - #[serde(borrow)] - type_name: Cow<'a, str>, + const NAME: &'static str = "DynSimOnly"; } impl Serialize for DynSimOnly { @@ -1309,11 +1245,7 @@ impl Serialize for DynSimOnly { where S: Serializer, { - DynSimOnlySerde { - random_id: (*self).into(), - type_name: Cow::Borrowed(self.type_name()), - } - .serialize(serializer) + SerdeById { inner: *self }.serialize(serializer) } } @@ -1322,16 +1254,7 @@ impl<'de> Deserialize<'de> for DynSimOnly { where D: Deserializer<'de>, { - let deserialized = DynSimOnlySerde::deserialize(deserializer)?; - let retval = deserialized - .random_id - .ty() - .filter(|ty| ty.type_name() == deserialized.type_name); - retval.ok_or_else(|| { - D::Error::custom( - "doesn't match any DynSimOnly that was serialized this time this program was run", - ) - }) + Ok(SerdeById::deserialize(deserializer)?.inner) } } diff --git a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs index 2424c03..bcbcdc6 100644 --- a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs +++ b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs @@ -3,7 +3,10 @@ //! `unsafe` parts of [`DynSimOnlyValue`] -use crate::expr::{ValueType, value_category::ValueCategoryValue}; +use crate::{ + expr::{ValueType, value_category::ValueCategoryValue}, + util::serde_by_id::SerdeByIdProperties, +}; use serde::{Serialize, de::DeserializeOwned}; use std::{ any::{self, TypeId}, @@ -33,6 +36,7 @@ unsafe trait DynSimOnlyTrait: 'static + Send + Sync { &self, json_str: &str, ) -> serde_json::Result>; + fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties; } /// Safety: `type_id_dyn` is implemented correctly @@ -55,6 +59,9 @@ unsafe impl DynSimOnlyTrait for SimOnly { ) -> serde_json::Result> { Ok(Rc::::new(serde_json::from_str(json_str)?)) } + fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties { + SerdeByIdProperties::of::() + } } /// Safety: @@ -151,6 +158,9 @@ impl DynSimOnly { pub fn default_value(self) -> DynSimOnlyValue { DynSimOnlyValue(self.ty.default_value()) } + pub(super) fn serde_by_id_properties_inner(self) -> SerdeByIdProperties { + self.ty.serde_by_id_properties_inner() + } } impl PartialEq for DynSimOnly { diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index 2988a7d..ab69532 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -6,7 +6,7 @@ use crate::{ bundle::{Bundle, BundleField, BundleType}, clock::Clock, enum_::{Enum, EnumType, EnumVariant}, - expr::{Expr, ToExpr, ValueType, ops}, + expr::{Expr, HdlPartialEqImpl, HdlPartialOrdImpl, ToExpr, ValueType, Valueless, ops}, int::{Bool, SInt, UInt, UIntValue}, intern::{Intern, Interned, LazyInterned, Memoize, SupportsPtrEqWithTypeId}, module::transform::visit::{Fold, Folder, Visit, Visitor}, @@ -23,6 +23,7 @@ use crate::{ use bitvec::{slice::BitSlice, vec::BitVec}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; use std::{ + borrow::Cow, fmt::{self, Write}, hash::Hash, iter::{FusedIterator, Sum}, @@ -997,9 +998,6 @@ impl OpaqueSimValue { pub fn sim_only_values(&self) -> &[DynSimOnlyValue] { &self.sim_only_values } - pub(crate) fn sim_only_values_vec(&self) -> &Vec { - &self.sim_only_values - } pub fn sim_only_values_mut(&mut self) -> &mut Vec { &mut self.sim_only_values } @@ -1463,14 +1461,14 @@ impl SimValueDebug for TraceAsString { value: &::SimValue, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { - T::sim_value_debug(value, f) + T::sim_value_debug(value.inner(), f) } } impl Type for TraceAsString { type BaseType = TraceAsString; type MaskType = T::MaskType; - type SimValue = TraceAsStringSimValue; + type SimValue = TraceAsStringSimValue; type MatchVariant = Expr; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -1507,7 +1505,8 @@ impl Type for TraceAsString { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { TraceAsStringSimValue { - inner: self.inner_ty.sim_value_from_opaque(opaque), + inner: SimValue::from_opaque(self.inner_ty(), opaque.to_owned()), + trace_as_string: self.trace_as_string.interned(), } } @@ -1594,101 +1593,217 @@ impl Index for TraceAsStringWithoutGenerics { } } -#[derive(Copy, Clone, Eq, Ord, Hash, Default, Serialize, Deserialize)] -pub struct TraceAsStringSimValue { +#[derive(Clone)] +pub struct TraceAsStringSimValue { + inner: SimValue, + trace_as_string: Interned, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename = "TraceAsStringSimValue")] +struct TraceAsStringSimValueSerde { inner: T, + trace_as_string: crate::util::serde_by_id::SerdeById>, } -impl TraceAsStringSimValue { - pub const fn new(inner: T) -> Self { - Self { inner } - } - pub fn into_inner(this: Self) -> T { - let Self { inner } = this; - inner +impl + Serialize> Serialize for TraceAsStringSimValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let Self { + inner, + trace_as_string, + } = self; + TraceAsStringSimValueSerde { + inner, + trace_as_string: crate::util::serde_by_id::SerdeById { + inner: *trace_as_string, + }, + } + .serialize(serializer) } } -impl ValueType for TraceAsStringSimValue { - type Type = TraceAsString; - type ValueCategory = T::ValueCategory; - - fn ty(&self) -> Self::Type { - TraceAsString::new(self.inner.ty()) - } -} - -impl ToExpr for TraceAsStringSimValue { - fn to_expr(&self) -> Expr { - let inner = self.inner.to_expr(); - ops::AsTraceAsString::new(Expr::canonical(inner), TraceAsString::new(inner.ty())).to_expr() - } -} - -impl, Ty: Type> ToSimValueWithType> +impl<'de, T: Type> + Deserialize<'de>> Deserialize<'de> for TraceAsStringSimValue { - fn to_sim_value_with_type(&self, ty: TraceAsString) -> SimValue> { - let inner = self.inner.to_sim_value_with_type(ty.inner_ty()); - let inner = SimValue::into_value(inner); - SimValue::from_value(ty, TraceAsStringSimValue { inner }) - } - fn into_sim_value_with_type(self, ty: TraceAsString) -> SimValue> { - let inner = self.inner.into_sim_value_with_type(ty.inner_ty()); - let inner = SimValue::into_value(inner); - SimValue::from_value(ty, TraceAsStringSimValue { inner }) + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let TraceAsStringSimValueSerde { + inner, + trace_as_string: + crate::util::serde_by_id::SerdeById { + inner: trace_as_string, + }, + } = Deserialize::deserialize(deserializer)?; + Ok(Self { + inner, + trace_as_string, + }) } } -impl ToSimValue for TraceAsStringSimValue { - fn to_sim_value(&self) -> SimValue { - self.to_sim_value_with_type(self.ty()) +impl TraceAsStringSimValue { + pub fn new_with_ty(inner: impl ToSimValueWithType, ty: TraceAsString) -> Self { + Self { + inner: inner.into_sim_value_with_type(ty.inner_ty()), + trace_as_string: ty.trace_as_string.interned(), + } } - fn into_sim_value(self) -> SimValue { - let ty = self.ty(); - self.into_sim_value_with_type(ty) + pub fn new(inner: impl ToSimValue) -> Self { + let inner = inner.into_sim_value(); + Self { + trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(), + inner, + } } -} - -impl std::ops::Deref for TraceAsStringSimValue { - type Target = T; - - fn deref(&self) -> &Self::Target { + pub fn into_inner(self) -> SimValue { + self.inner + } + pub fn inner(&self) -> &SimValue { &self.inner } -} - -impl std::ops::DerefMut for TraceAsStringSimValue { - fn deref_mut(&mut self) -> &mut Self::Target { + pub fn inner_mut(&mut self) -> &mut SimValue { &mut self.inner } } -impl fmt::Debug for TraceAsStringSimValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner } = self; - fmt::Debug::fmt(inner, f) +impl ValueType for TraceAsStringSimValue { + type Type = TraceAsString; + type ValueCategory = crate::expr::value_category::ValueCategoryValue; + + fn ty(&self) -> Self::Type { + let inner_ty = self.inner.ty().intern_sized(); + if self + .trace_as_string + .can_substitute_type(inner_ty.canonical()) + { + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: LazyInterned::Interned(self.trace_as_string), + } + } else { + TraceAsString::new_interned(inner_ty) + } } } -impl fmt::Display for TraceAsStringSimValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner } = self; - fmt::Display::fmt(inner, f) +impl ToExpr for TraceAsStringSimValue { + #[track_caller] + fn to_expr(&self) -> Expr { + let inner = self.inner.to_expr(); + let inner_canonical = Expr::canonical(inner); + let inner_ty = inner.ty().intern_sized(); + let ty = if self + .trace_as_string + .can_substitute_type(inner_canonical.ty()) + { + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: LazyInterned::Interned(self.trace_as_string), + } + } else { + TraceAsString::new_interned(inner_ty) + }; + ops::ToTraceAsString::new(inner_canonical, ty).to_expr() } } -impl, U> PartialOrd> for TraceAsStringSimValue { +impl ToSimValueWithType> for TraceAsStringSimValue { + fn to_sim_value_with_type(&self, ty: TraceAsString) -> SimValue> { + let inner = self.inner.to_sim_value_with_type(ty.inner_ty()); + SimValue::from_value( + ty, + TraceAsStringSimValue { + inner, + trace_as_string: ty.trace_as_string.interned(), + }, + ) + } + fn into_sim_value_with_type(self, ty: TraceAsString) -> SimValue> { + let inner = self.inner.into_sim_value_with_type(ty.inner_ty()); + SimValue::from_value( + ty, + TraceAsStringSimValue { + inner, + trace_as_string: ty.trace_as_string.interned(), + }, + ) + } +} + +impl ToSimValue for TraceAsStringSimValue { + fn to_sim_value(&self) -> SimValue { + SimValue::from_value(self.ty(), self.clone()) + } + fn into_sim_value(self) -> SimValue { + SimValue::from_value(self.ty(), self) + } +} + +impl fmt::Debug for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} + +impl> fmt::Display for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.inner, f) + } +} + +impl Ord for TraceAsStringSimValue +where + SimValue: Ord, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.inner.cmp(&other.inner) + } +} + +impl PartialOrd> for TraceAsStringSimValue +where + SimValue: PartialOrd>, +{ fn partial_cmp(&self, other: &TraceAsStringSimValue) -> Option { - let Self { inner } = self; - inner.partial_cmp(&other.inner) + self.inner.partial_cmp(&other.inner) } } -impl, U> PartialEq> for TraceAsStringSimValue { +impl Eq for TraceAsStringSimValue where SimValue: Eq {} + +impl Hash for TraceAsStringSimValue +where + SimValue: Hash, +{ + fn hash(&self, state: &mut H) { + self.inner.hash(state); + } +} + +impl Default for TraceAsStringSimValue +where + SimValue: Default, +{ + fn default() -> Self { + let inner = SimValue::default(); + Self { + trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(), + inner, + } + } +} + +impl PartialEq> for TraceAsStringSimValue +where + SimValue: PartialEq>, +{ fn eq(&self, other: &TraceAsStringSimValue) -> bool { - let Self { inner } = self; - *inner == other.inner + self.inner == other.inner } } @@ -1711,3 +1826,259 @@ impl, State: ?Sized + Visitor> Visit for TraceAsSt self.interned_inner_ty().visit(state) } } + +fn trace_as_string_cow_into_inner( + this: Cow<'_, SimValue>>, +) -> Cow<'_, SimValue> { + match this { + Cow::Borrowed(v) => Cow::Borrowed(&v.inner), + Cow::Owned(v) => Cow::Owned(SimValue::into_value(v).inner), + } +} + +fn trace_as_string_cow_into_inner_value( + this: Cow<'_, TraceAsStringSimValue>, +) -> Cow<'_, T::SimValue> { + match this { + Cow::Borrowed(v) => Cow::Borrowed(&v.inner), + Cow::Owned(v) => Cow::Owned(SimValue::into_value(v.inner)), + } +} + +impl, U: Type> HdlPartialEqImpl> for TraceAsString { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialEqImpl::cmp_value_eq( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_ne( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialEqImpl::cmp_value_ne( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialEqImpl::cmp_sim_value_eq( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialEqImpl::cmp_sim_value_ne( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialEqImpl::cmp_expr_eq(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_ne(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialEqImpl::cmp_expr_ne(*lhs, *rhs) + } + + #[track_caller] + fn cmp_valueless_eq(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialEqImpl::cmp_valueless_eq( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_ne(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialEqImpl::cmp_valueless_ne( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } +} + +impl, U: Type> HdlPartialOrdImpl> for TraceAsString { + #[track_caller] + fn cmp_value_lt( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_lt( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_le( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_le( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_gt( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_gt( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_ge( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_ge( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_sim_value_lt( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_lt( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_le( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_le( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_gt( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_gt( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_ge( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_ge( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_expr_lt(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_lt(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_le(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_le(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_gt(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_gt(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_ge(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_ge(*lhs, *rhs) + } + + #[track_caller] + fn cmp_valueless_lt(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_lt( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_le(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_le( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_gt(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_gt( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_ge(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_ge( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } +} diff --git a/crates/fayalite/src/ty/serde_impls.rs b/crates/fayalite/src/ty/serde_impls.rs index 126c4b0..d5b5551 100644 --- a/crates/fayalite/src/ty/serde_impls.rs +++ b/crates/fayalite/src/ty/serde_impls.rs @@ -39,6 +39,7 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst< #[derive(Serialize, Deserialize)] #[serde(rename = "CanonicalType")] +#[expect(private_interfaces)] pub(crate) enum SerdeCanonicalType< ArrayElement = CanonicalType, ThePhantomConst = SerdePhantomConst>, diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 238259c..176c3fe 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -13,7 +13,7 @@ use fayalite::{ prelude::*, reset::ResetType, sim::vcd::VcdWriterDecls, - ty::{SimValueDebug, StaticType, TraceAsString, TraceAsStringSimValue}, + ty::SimValueDebug, util::{RcWriter, ready_valid::queue}, }; use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc}; @@ -3061,10 +3061,7 @@ pub fn sim_trace_as_string() { #[hdl] let write: WriteStruct, 2>, ConstUsize<8>> = m.input(); #[hdl] - let mut mem = memory_with_init( - [[Expr::as_trace_as_string(HasCustomDebug::new_sim(Ok("")).to_expr(), StaticType::TYPE); 2]; - 4], - ); + let mut mem = memory_with_init([[HasCustomDebug::new_sim(Ok("")).to_trace_as_string(); 2]; 4]); let read_port = mem.new_read_port(); connect(read_port.clk, clk); connect_any(read_port.addr, read.addr); @@ -3156,7 +3153,7 @@ fn test_sim_trace_as_string() { sim.write(sim.io().write.en, write_addr.is_some()); sim.write( sim.io().write.data, - write_data.map(|v| TraceAsStringSimValue::new(HasCustomDebug::new_sim(v))), + write_data.map(|v| HasCustomDebug::new_sim(v).to_trace_as_string()), ); sim.write( sim.io().write.mask, @@ -3172,7 +3169,7 @@ fn test_sim_trace_as_string() { .map(HasCustomDebug::new_sim) .into_sim_value(); assert!( - **read_data == *expected_read_data, + *read_data.inner() == expected_read_data, "{read_data:#?}\n!= {expected_read_data:#?}", ); } diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr index dbdf937..8eff725 100644 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr @@ -55,7 +55,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -75,12 +75,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 895 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -95,7 +95,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `fayalite::intern::Interned` --> src/intern.rs @@ -194,7 +194,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -214,12 +214,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 895 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -234,7 +234,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `intern_sized` --> src/intern.rs @@ -306,7 +306,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -326,12 +326,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 895 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -346,7 +346,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `fayalite::intern::Interned` --> src/intern.rs diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index f5d666c..f3af962 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -1022,10 +1022,10 @@ "fold_where": "T: Fold", "visit_where": "T: Visit" }, - "ops::AsTraceAsString": { + "ops::ToTraceAsString": { "data": { "$kind": "Struct", - "$constructor": "ops::AsTraceAsString::new", + "$constructor": "ops::ToTraceAsString::new", "inner()": "Visible", "ty()": "Visible" }, @@ -1310,7 +1310,7 @@ "$kind": "Struct" } }, - "TargetPathAsTraceAsString": { + "TargetPathToTraceAsString": { "data": { "$kind": "Struct", "ty": "Visible" @@ -1323,7 +1323,7 @@ "ArrayElement": "Visible", "DynArrayElement": "Visible", "TraceAsStringInner": "Visible", - "AsTraceAsString": "Visible" + "ToTraceAsString": "Visible" } }, "PhantomConst": {