diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index f952f426..3a3d3cee 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -396,15 +396,29 @@ impl ToTokens for Builder { quote_spanned! {self.ident.span()=> #[automatically_derived] #[allow(non_camel_case_types, dead_code, private_interfaces)] - impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty + impl #filled_impl_generics ::fayalite::expr::ValueType for #filled_ty #filled_where_clause { type Type = #target #type_generics; + type ValueCategory = ::fayalite::expr::value_category::ValueCategoryExpr; + + fn ty(&self) -> ::Type { + #target { + #(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)* + } + } + } + + #[automatically_derived] + #[allow(non_camel_case_types, dead_code, private_interfaces)] + impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty + #filled_where_clause + { fn to_expr( &self, - ) -> ::fayalite::expr::Expr<::Type> { + ) -> ::fayalite::expr::Expr<::Type> { let __ty = #target { - #(#field_idents: ::fayalite::expr::Expr::ty(self.#field_idents),)* + #(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)* }; let __field_values = [ #(::fayalite::expr::Expr::canonical(self.#field_idents),)* @@ -695,10 +709,10 @@ impl ToTokens for ParsedBundle { v.field(&value.#ident); } })); - let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { + let value_type_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); quote_spanned! {span=> - #ident: ::fayalite::sim::value::SimValue::ty(&self.#ident), + #ident: ::fayalite::expr::ValueType::ty(&self.#ident), } })); let fields_len = fields.named().into_iter().len(); @@ -806,28 +820,39 @@ impl ToTokens for ParsedBundle { } } #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics + impl #impl_generics ::fayalite::expr::ValueType for #mask_type_sim_value_ident #type_generics #where_clause { type Type = #mask_type_ident #type_generics; + type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue; + fn ty(&self) -> ::Type { + #mask_type_ident { + #(#value_type_fields)* + } + } + } + #[automatically_derived] + impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics + #where_clause + { fn to_sim_value( &self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { let ty = #mask_type_ident { - #(#to_sim_value_fields)* + #(#value_type_fields)* }; ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) } fn into_sim_value( self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { let ty = #mask_type_ident { - #(#to_sim_value_fields)* + #(#value_type_fields)* }; ::fayalite::sim::value::SimValue::from_value(ty, self) } @@ -955,28 +980,39 @@ impl ToTokens for ParsedBundle { } } #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics + impl #impl_generics ::fayalite::expr::ValueType for #sim_value_ident #type_generics #where_clause { type Type = #target #type_generics; + type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue; + fn ty(&self) -> ::Type { + #target { + #(#value_type_fields)* + } + } + } + #[automatically_derived] + impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics + #where_clause + { fn to_sim_value( &self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { let ty = #target { - #(#to_sim_value_fields)* + #(#value_type_fields)* }; ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) } fn into_sim_value( self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { let ty = #target { - #(#to_sim_value_fields)* + #(#value_type_fields)* }; ::fayalite::sim::value::SimValue::from_value(ty, self) } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index 885cf871..90838f0b 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -1024,16 +1024,26 @@ impl ToTokens for ParsedEnum { <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; } #[automatically_derived] - impl #static_impl_generics ::fayalite::sim::value::ToSimValue + impl #static_impl_generics ::fayalite::expr::ValueType for #sim_value_ident #static_type_generics #static_where_clause { type Type = #target #static_type_generics; + type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue; + fn ty(&self) -> ::Type { + ::fayalite::ty::StaticType::TYPE + } + } + #[automatically_derived] + impl #static_impl_generics ::fayalite::sim::value::ToSimValue + for #sim_value_ident #static_type_generics + #static_where_clause + { fn to_sim_value( &self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { ::fayalite::sim::value::SimValue::from_value( ::fayalite::ty::StaticType::TYPE, @@ -1043,7 +1053,7 @@ impl ToTokens for ParsedEnum { fn into_sim_value( self, ) -> ::fayalite::sim::value::SimValue< - ::Type, + ::Type, > { ::fayalite::sim::value::SimValue::from_value( ::fayalite::ty::StaticType::TYPE, diff --git a/crates/fayalite-proc-macros-impl/src/lib.rs b/crates/fayalite-proc-macros-impl/src/lib.rs index 13ec7a2e..152053cb 100644 --- a/crates/fayalite-proc-macros-impl/src/lib.rs +++ b/crates/fayalite-proc-macros-impl/src/lib.rs @@ -887,7 +887,13 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr } } let _print_on_panic = PrintOnPanic(&contents); - let contents = prettyplease::unparse(&parse_quote! { #contents }); + let mut parse_err = None; + let (Ok(contents) | Err(contents)) = syn::parse2(contents.clone()) + .map(|file| prettyplease::unparse(&file)) + .map_err(|e| { + parse_err = Some(e); + contents.to_string() + }); let hash = ::digest(&contents); let hash = base16ct::HexDisplay(&hash[..5]); file.write_all(contents.as_bytes()).unwrap(); @@ -899,9 +905,26 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr e.unwrap(); } } - eprintln!("generated {}", dest_file.display()); + let log_msg = if let Some(parse_err) = parse_err { + format!( + "fayalite-proc-macros-impl internal error:\nfailed to parse generated output: {parse_err}\nunformatted output is in: {}\n", + dest_file.display() + ) + } else { + format!("generated {}\n", dest_file.display()) + }; + // write message atomically if possible + let mut stderr = std::io::stderr().lock(); + let write_result = stderr.write_all(log_msg.as_bytes()); + let flush_result = stderr.flush(); + drop(stderr); // unlock before we try to panic + write_result.unwrap(); + flush_result.unwrap(); + std::io::stderr() + .lock() + .write_all(log_msg.as_bytes()) + .unwrap(); let dest_file = dest_file.to_str().unwrap(); - quote! { include!(#dest_file); } diff --git a/crates/fayalite/examples/blinky.rs b/crates/fayalite/examples/blinky.rs index 75799fdc..d2cdb336 100644 --- a/crates/fayalite/examples/blinky.rs +++ b/crates/fayalite/examples/blinky.rs @@ -12,7 +12,7 @@ fn blinky(platform_io_builder: PlatformIOBuilder<'_>) { clk: clk_input.clk, rst, }; - let max_value = (Expr::ty(clk_input).frequency() / 2.0).round_ties_even() as u64 - 1; + let max_value = (clk_input.ty().frequency() / 2.0).round_ties_even() as u64 - 1; let int_ty = UInt::range_inclusive(0..=max_value); #[hdl] let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty)); diff --git a/crates/fayalite/examples/tx_only_uart.rs b/crates/fayalite/examples/tx_only_uart.rs index 5c20b395..59e29682 100644 --- a/crates/fayalite/examples/tx_only_uart.rs +++ b/crates/fayalite/examples/tx_only_uart.rs @@ -105,7 +105,7 @@ fn tx_only_uart( connect(tx, tx_bits[uart_state_reg]); #[hdl] - if uart_state_reg.cmp_eq(Expr::ty(tx_bits).len() - 1) { + if uart_state_reg.cmp_eq(tx_bits.ty().len() - 1) { connect(next_uart_state, 0_hdl_u4); let next_addr_val = addr_reg + 1u8; #[hdl] diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 569f2e28..a07ebb4c 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -221,7 +221,7 @@ impl Type for ArrayType { let value = AsMut::<[SimValue]>::as_mut(value); assert_eq!(self.len(), value.len()); for element_value in value { - assert_eq!(SimValue::ty(element_value), element_ty); + assert_eq!(element_value.ty(), element_ty); let (element_opaque, rest) = opaque.split_at(element_size); SimValue::opaque_mut(element_value).clone_from_slice(element_opaque); opaque = rest; @@ -238,7 +238,7 @@ impl Type for ArrayType { let value = AsRef::<[SimValue]>::as_ref(value); assert_eq!(self.len(), value.len()); for element_value in value { - assert_eq!(SimValue::ty(element_value), element_ty); + assert_eq!(element_value.ty(), element_ty); writer.fill_prefix_with(element_size, |writer| { writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice()) }); @@ -331,9 +331,7 @@ where Lhs: ExprPartialEq, { fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); + assert_eq!(lhs.ty().len(), rhs.ty().len()); lhs.into_iter() .zip(rhs) .map(|(l, r)| l.cmp_eq(r)) @@ -343,9 +341,7 @@ where } fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); + assert_eq!(lhs.ty().len(), rhs.ty().len()); lhs.into_iter() .zip(rhs) .map(|(l, r)| l.cmp_ne(r)) @@ -374,7 +370,7 @@ impl ExprIntoIterator for ArrayType { fn expr_into_iter(e: Expr) -> Self::ExprIntoIter { ExprArrayIter { base: e, - indexes: 0..Expr::ty(e).len(), + indexes: 0..e.ty().len(), } } } diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 0edf1928..04689c84 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -3,8 +3,9 @@ use crate::{ expr::{ - CastToBits, Expr, ReduceBits, ToExpr, + CastToBits, Expr, ReduceBits, ToExpr, ToSimValueInner, ValueType, ops::{ArrayLiteral, BundleLiteral, ExprPartialEq}, + value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue}, }, int::{Bool, DynSize}, intern::{Intern, InternSlice, Interned}, @@ -317,7 +318,7 @@ impl<'a> BundleSimValueFromOpaque<'a> { #[track_caller] pub fn field_clone_from_opaque(&mut self, field_value: &mut SimValue) { let (field_ty, field_opaque) = self.field_ty_and_opaque::(); - assert_eq!(field_ty, SimValue::ty(field_value)); + assert_eq!(field_ty, field_value.ty()); SimValue::opaque_mut(field_value).clone_from_slice(field_opaque); } } @@ -353,7 +354,7 @@ impl<'a> BundleSimValueToOpaque<'a> { else { panic!("tried to write too many fields with BundleSimValueToOpaque"); }; - assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); + assert_eq!(T::from_canonical(ty), field_value.ty()); self.writer.fill_prefix_with(ty.size(), |writer| { writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice()) }); @@ -566,23 +567,54 @@ macro_rules! impl_tuples { builder.finish() }; } - impl<$($T: ToExpr,)*> ToExpr for ($($T,)*) { + impl<$($T: ToSimValue,)*> ToSimValueInner for ($($T,)*) + where + Self: ValueType, + { + fn to_sim_value_inner(this: &Self) -> ::SimValue { + let ($($var,)*) = this; + ($($var.to_sim_value(),)*) + } + fn into_sim_value_inner(this: Self) -> ::SimValue { + let ($($var,)*) = this; + ($($var.into_sim_value(),)*) + } + } + impl<$($T: ValueType,)*> ValueType for ($($T,)*) + where + ValueCategoryValue: ValueCategoryCommon<($($T::ValueCategory,)*)>, + { type Type = ($($T::Type,)*); - + type ValueCategory = >::Common; + fn ty(&self) -> Self::Type { + let ($($var,)*) = self; + ($($var.ty(),)*) + } + } + impl<$($T: ToExpr,)*> ToExpr for ($($T,)*) + where + Self: ValueType, + { fn to_expr(&self) -> Expr { let ($($var,)*) = self; $(let $var = $var.to_expr();)* - let ty = ($(Expr::ty($var),)*); + let ty = ($($var.ty(),)*); let field_values = [$(Expr::canonical($var)),*]; BundleLiteral::new(ty, field_values.intern_slice()).to_expr() } } - impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> { + impl<$($T: Type,)*> ValueType for TupleBuilder<($(Expr<$T>,)*)> { type Type = ($($T,)*); - + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + let ($($var,)*) = self.0; + ($($var.ty(),)*) + } + } + impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> { fn to_expr(&self) -> Expr { let ($($var,)*) = self.0; - let ty = ($(Expr::ty($var),)*); + let ty = ($($var.ty(),)*); let field_values = [$(Expr::canonical($var)),*]; BundleLiteral::new(ty, field_values.intern_slice()).to_expr() } @@ -618,7 +650,7 @@ macro_rules! impl_tuples { }; let mut opaque = OpaqueSimValue::empty(); $(let $var = $var.into_sim_value_with_type($ty_var.ty); - assert_eq!(SimValue::ty(&$var), $ty_var.ty); + assert_eq!($var.ty(), $ty_var.ty); opaque.extend_from_slice(SimValue::opaque(&$var).as_slice()); )* SimValue::from_opaque(ty, opaque) @@ -640,19 +672,21 @@ macro_rules! impl_tuples { SimValue::from_value(ty, ($($var,)*)) } } - impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { - type Type = ($($T::Type,)*); + impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) + where + Self: ValueType, + { #[track_caller] fn to_sim_value(&self) -> SimValue { let ($($var,)*) = self; $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) + SimValue::from_value(($($var.ty(),)*), ($($var,)*)) } #[track_caller] fn into_sim_value(self) -> SimValue { let ($($var,)*) = self; $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) + SimValue::from_value(($($var.ty(),)*), ($($var,)*)) } } impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { @@ -775,9 +809,16 @@ impl Default for PhantomDataBuilder { } } -impl ToExpr for PhantomDataBuilder { +impl ValueType for PhantomDataBuilder { type Type = PhantomData; + type ValueCategory = ValueCategoryValue; + fn ty(&self) -> Self::Type { + PhantomData + } +} + +impl ToExpr for PhantomDataBuilder { fn to_expr(&self) -> Expr { PhantomData.to_expr() } @@ -803,17 +844,22 @@ impl StaticType for PhantomData { const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; } -impl ToExpr for PhantomData { +impl ValueType for PhantomData { type Type = PhantomData; + type ValueCategory = ValueCategoryValue; + fn ty(&self) -> Self::Type { + PhantomData + } +} + +impl ToExpr for PhantomData { fn to_expr(&self) -> Expr { BundleLiteral::new(PhantomData, Interned::default()).to_expr() } } impl ToSimValue for PhantomData { - type Type = PhantomData; - #[track_caller] fn to_sim_value(&self) -> SimValue { SimValue::from_value(*self, *self) diff --git a/crates/fayalite/src/clock.rs b/crates/fayalite/src/clock.rs index 909edbdf..168142b7 100644 --- a/crates/fayalite/src/clock.rs +++ b/crates/fayalite/src/clock.rs @@ -1,10 +1,11 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - expr::{Expr, ToExpr}, + expr::{Expr, ValueType}, hdl, int::Bool, reset::{Reset, ResetType}, + sim::value::SimValue, source_location::SourceLocation, ty::{ CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, @@ -91,29 +92,34 @@ impl StaticType for Clock { } pub trait ToClock { - fn to_clock(&self) -> Expr; + type Output: ValueType; + fn to_clock(&self) -> Self::Output; } impl ToClock for &'_ T { - fn to_clock(&self) -> Expr { + type Output = T::Output; + fn to_clock(&self) -> Self::Output { (**self).to_clock() } } impl ToClock for &'_ mut T { - fn to_clock(&self) -> Expr { + type Output = T::Output; + fn to_clock(&self) -> Self::Output { (**self).to_clock() } } impl ToClock for Box { - fn to_clock(&self) -> Expr { + type Output = T::Output; + fn to_clock(&self) -> Self::Output { (**self).to_clock() } } impl ToClock for Expr { - fn to_clock(&self) -> Expr { + type Output = Expr; + fn to_clock(&self) -> Self::Output { *self } } @@ -125,7 +131,25 @@ pub struct ClockDomain { } impl ToClock for bool { - fn to_clock(&self) -> Expr { - self.to_expr().to_clock() + type Output = SimValue; + + fn to_clock(&self) -> Self::Output { + SimValue::from_value(Clock, *self) + } +} + +impl ToClock for SimValue { + type Output = SimValue; + + fn to_clock(&self) -> Self::Output { + SimValue::from_value(Clock, **self) + } +} + +impl ToClock for SimValue { + type Output = SimValue; + + fn to_clock(&self) -> Self::Output { + self.clone() } } diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 083072b5..e1a6dfa3 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -3,7 +3,7 @@ use crate::{ expr::{ - Expr, ToExpr, + Expr, ToExpr, ValueType, ops::{ExprPartialEq, VariantAccess}, }, hdl, @@ -599,7 +599,7 @@ impl<'a> EnumSimValueFromOpaque<'a> { let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else { self.usage_error(true); }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); + assert_eq!(value.ty(), T::from_canonical(variant_ty)); SimValue::bits_mut(value) .bits_mut() .copy_from_bitslice(variant_bits); @@ -711,7 +711,7 @@ impl<'a> EnumSimValueToOpaque<'a> { let Some(variant_ty) = self.variants[discriminant].ty else { panic!("expected variant to have no field"); }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); + assert_eq!(value.ty(), T::from_canonical(variant_ty)); self.known_variant(discriminant, Some(SimValue::opaque(value)), padding) } } @@ -813,7 +813,7 @@ pub fn HdlNone() -> Expr> { #[allow(non_snake_case)] pub fn HdlSome(value: impl ToExpr) -> Expr> { let value = value.to_expr(); - HdlOption[Expr::ty(value)].HdlSome(value) + HdlOption[value.ty()].HdlSome(value) } impl HdlOption { @@ -853,7 +853,7 @@ impl HdlOption { let value = f(value).inspect_err(|_| { and_then_out.complete(()); // avoid error })?; - let and_then_out = and_then_out.complete(Expr::ty(value)); + let and_then_out = and_then_out.complete(value.ty()); connect(and_then_out, value); drop(some_scope); let (Wrap::<::MatchVariant>::HdlNone, none_scope) = @@ -861,7 +861,7 @@ impl HdlOption { else { unreachable!(); }; - connect(and_then_out, Expr::ty(and_then_out).HdlNone()); + connect(and_then_out, and_then_out.ty().HdlNone()); drop(none_scope); Ok(and_then_out) } @@ -879,8 +879,8 @@ impl HdlOption { #[track_caller] pub fn and(expr: Expr, opt_b: Expr>) -> Expr> { #[hdl] - let and_out = wire(Expr::ty(opt_b)); - connect(and_out, Expr::ty(opt_b).HdlNone()); + let and_out = wire(opt_b.ty()); + connect(and_out, opt_b.ty().HdlNone()); #[hdl] if let HdlSome(_) = expr { connect(and_out, opt_b); @@ -894,8 +894,8 @@ impl HdlOption { f: impl FnOnce(Expr) -> Result, E>, ) -> Result, E> { #[hdl] - let filtered = wire(Expr::ty(expr)); - connect(filtered, Expr::ty(expr).HdlNone()); + let filtered = wire(expr.ty()); + connect(filtered, expr.ty().HdlNone()); let mut f = Some(f); #[hdl] if let HdlSome(v) = expr { @@ -969,7 +969,7 @@ impl HdlOption { f: impl FnOnce(Expr) -> Expr, ) -> Expr { #[hdl] - let mapped = wire(Expr::ty(default)); + let mapped = wire(default.ty()); let mut f = Some(f); #[hdl] match expr { @@ -994,12 +994,12 @@ impl HdlOption { match expr { HdlSome(v) => { let v = f.take().unwrap()(v); - let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v))); + let mapped = *retval.get_or_insert_with(|| mapped.complete(v.ty())); connect(mapped, v); } HdlNone => { let v = default.take().unwrap()(); - let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v))); + let mapped = *retval.get_or_insert_with(|| mapped.complete(v.ty())); connect(mapped, v); } } @@ -1009,7 +1009,7 @@ impl HdlOption { #[track_caller] pub fn or(expr: Expr, opt_b: Expr) -> Expr { #[hdl] - let or_out = wire(Expr::ty(expr)); + let or_out = wire(expr.ty()); connect(or_out, opt_b); #[hdl] if let HdlSome(_) = expr { @@ -1021,7 +1021,7 @@ impl HdlOption { #[track_caller] pub fn or_else(expr: Expr, f: impl FnOnce() -> Expr) -> Expr { #[hdl] - let or_else_out = wire(Expr::ty(expr)); + let or_else_out = wire(expr.ty()); connect(or_else_out, f()); #[hdl] if let HdlSome(_) = expr { @@ -1033,7 +1033,7 @@ impl HdlOption { #[track_caller] pub fn unwrap_or(expr: Expr, default: Expr) -> Expr { #[hdl] - let unwrap_or_else_out = wire(Expr::ty(default)); + let unwrap_or_else_out = wire(default.ty()); connect(unwrap_or_else_out, default); #[hdl] if let HdlSome(v) = expr { @@ -1045,7 +1045,7 @@ impl HdlOption { #[track_caller] pub fn unwrap_or_else(expr: Expr, f: impl FnOnce() -> Expr) -> Expr { #[hdl] - let unwrap_or_else_out = wire(Expr::ty(expr).HdlSome); + let unwrap_or_else_out = wire(expr.ty().HdlSome); connect(unwrap_or_else_out, f()); #[hdl] if let HdlSome(v) = expr { @@ -1057,14 +1057,14 @@ impl HdlOption { #[track_caller] pub fn xor(expr: Expr, opt_b: Expr) -> Expr { #[hdl] - let xor_out = wire(Expr::ty(expr)); + let xor_out = wire(expr.ty()); #[hdl] if let HdlSome(_) = expr { #[hdl] if let HdlNone = opt_b { connect(xor_out, expr); } else { - connect(xor_out, Expr::ty(expr).HdlNone()); + connect(xor_out, expr.ty().HdlNone()); } } else { connect(xor_out, opt_b); @@ -1075,8 +1075,8 @@ impl HdlOption { #[track_caller] pub fn zip(expr: Expr, other: Expr>) -> Expr> { #[hdl] - let zip_out = wire(HdlOption[(Expr::ty(expr).HdlSome, Expr::ty(other).HdlSome)]); - connect(zip_out, Expr::ty(zip_out).HdlNone()); + let zip_out = wire(HdlOption[(expr.ty().HdlSome, other.ty().HdlSome)]); + connect(zip_out, zip_out.ty().HdlNone()); #[hdl] if let HdlSome(l) = expr { #[hdl] @@ -1093,11 +1093,11 @@ impl HdlOption> { #[track_caller] pub fn flatten(expr: Expr) -> Expr> { #[hdl] - let flattened = wire(Expr::ty(expr).HdlSome); + let flattened = wire(expr.ty().HdlSome); #[hdl] match expr { HdlSome(v) => connect(flattened, v), - HdlNone => connect(flattened, Expr::ty(expr).HdlSome.HdlNone()), + HdlNone => connect(flattened, expr.ty().HdlSome.HdlNone()), } flattened } @@ -1107,7 +1107,7 @@ impl HdlOption<(T, U)> { #[hdl] #[track_caller] pub fn unzip(expr: Expr) -> Expr<(HdlOption, HdlOption)> { - let (t, u) = Expr::ty(expr).HdlSome; + let (t, u) = expr.ty().HdlSome; #[hdl] let unzipped = wire((HdlOption[t], HdlOption[u])); connect(unzipped, (HdlOption[t].HdlNone(), HdlOption[u].HdlNone())); diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 89e60cda..45e02234 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -9,7 +9,7 @@ use crate::{ ops::ExprCastTo, target::{GetTarget, Target}, }, - int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue}, + int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{DynPortType, MemPort, PortType}, module::{ @@ -20,6 +20,7 @@ use crate::{ reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, ty::{CanonicalType, StaticType, Type, TypeWithDeref}, + util::ConstBool, wire::Wire, }; use bitvec::slice::BitSlice; @@ -27,6 +28,7 @@ use std::{convert::Infallible, fmt, ops::Deref}; pub mod ops; pub mod target; +pub mod value_category; macro_rules! expr_enum { ( @@ -77,9 +79,18 @@ macro_rules! expr_enum { } } - impl ToExpr for $ExprEnum { + impl ValueType for $ExprEnum { type Type = CanonicalType; + type ValueCategory = value_category::ValueCategoryExpr; + fn ty(&self) -> Self::Type { + match self { + $(Self::$Variant(v) => v.ty().canonical(),)* + } + } + } + + impl ToExpr for $ExprEnum { fn to_expr(&self) -> Expr { match self { $(Self::$Variant(v) => Expr::canonical(v.to_expr()),)* @@ -282,7 +293,7 @@ impl fmt::Debug for Expr { __flow, } = self; let expr_ty = __ty.canonical(); - let enum_ty = __enum.to_expr().__ty; + let enum_ty = __enum.to_expr().ty(); assert_eq!( expr_ty, enum_ty, "expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}" @@ -296,23 +307,20 @@ impl Expr { pub fn expr_enum(this: Self) -> Interned { this.__enum } - pub fn ty(this: Self) -> T { - this.__ty - } pub fn flow(this: Self) -> Flow { this.__flow } pub fn canonical(this: Self) -> Expr { Expr { __enum: this.__enum, - __ty: this.__ty.canonical(), + __ty: this.ty().canonical(), __flow: this.__flow, } } pub fn from_canonical(this: Expr) -> Self { Expr { __enum: this.__enum, - __ty: T::from_canonical(this.__ty), + __ty: T::from_canonical(this.ty()), __flow: this.__flow, } } @@ -322,7 +330,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: T::from_dyn_int(this.__ty), + __ty: T::from_dyn_int(this.ty()), __flow: this.__flow, } } @@ -332,7 +340,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: this.__ty.as_dyn_int(), + __ty: this.ty().as_dyn_int(), __flow: this.__flow, } } @@ -342,7 +350,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: Bundle::new(this.__ty.fields()), + __ty: Bundle::new(this.ty().fields()), __flow: this.__flow, } } @@ -352,7 +360,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: T::from_canonical(CanonicalType::Bundle(this.__ty)), + __ty: T::from_canonical(CanonicalType::Bundle(this.ty())), __flow: this.__flow, } } @@ -369,7 +377,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: Enum::new(this.__ty.variants()), + __ty: Enum::new(this.ty().variants()), __flow: this.__flow, } } @@ -379,7 +387,7 @@ impl Expr { { Expr { __enum: this.__enum, - __ty: T::from_canonical(CanonicalType::Enum(this.__ty)), + __ty: T::from_canonical(CanonicalType::Enum(this.ty())), __flow: this.__flow, } } @@ -409,7 +417,7 @@ impl Expr> { pub fn as_dyn_array(this: Self) -> Expr { Expr { __enum: this.__enum, - __ty: this.__ty.as_dyn_array(), + __ty: this.ty().as_dyn_array(), __flow: this.__flow, } } @@ -435,54 +443,41 @@ impl Visit for Expr { } } -pub trait ToExpr { - type Type: Type; +pub trait ToExpr: ValueType + ToValueless { fn to_expr(&self) -> Expr; } impl ToExpr for Expr { - type Type = T; - fn to_expr(&self) -> Expr { *self } } impl ToExpr for &'_ T { - type Type = T::Type; - fn to_expr(&self) -> Expr { T::to_expr(self) } } impl ToExpr for &'_ mut T { - type Type = T::Type; - fn to_expr(&self) -> Expr { T::to_expr(self) } } impl ToExpr for Box { - type Type = T::Type; - fn to_expr(&self) -> Expr { T::to_expr(self) } } impl ToExpr for Interned { - type Type = T::Type; - fn to_expr(&self) -> Expr { T::to_expr(self) } } impl ToExpr for UIntValue { - type Type = UIntType; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::UIntLiteral(self.clone().as_dyn_int().intern()).intern(), @@ -493,8 +488,6 @@ impl ToExpr for UIntValue { } impl ToExpr for SIntValue { - type Type = SIntType; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::SIntLiteral(self.clone().as_dyn_int().intern()).intern(), @@ -504,9 +497,16 @@ impl ToExpr for SIntValue { } } -impl ToExpr for bool { +impl ValueType for bool { type Type = Bool; + type ValueCategory = value_category::ValueCategoryValue; + fn ty(&self) -> Self::Type { + Bool + } +} + +impl ToExpr for bool { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::BoolLiteral(*self).intern(), @@ -537,8 +537,6 @@ impl Flow { } impl ToExpr for ModuleIO { - type Type = T; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::ModuleIO(self.canonical()).intern_sized(), @@ -561,8 +559,6 @@ impl GetTarget for ModuleIO { } impl ToExpr for Instance { - type Type = T; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::Instance(self.canonical()).intern_sized(), @@ -585,8 +581,6 @@ impl GetTarget for Instance { } impl ToExpr for Wire { - type Type = T; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::Wire(self.canonical()).intern_sized(), @@ -609,8 +603,6 @@ impl GetTarget for Wire { } impl ToExpr for Reg { - type Type = T; - fn to_expr(&self) -> Expr { struct Dispatch; impl ResetTypeDispatch for Dispatch { @@ -650,8 +642,6 @@ impl GetTarget for Reg { } impl ToExpr for MemPort { - type Type = T::Port; - fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::MemPort(self.canonical()).intern_sized(), @@ -674,20 +664,21 @@ impl GetTarget for MemPort { } pub trait HdlPartialEq { - fn cmp_eq(self, rhs: Rhs) -> Expr; - fn cmp_ne(self, rhs: Rhs) -> Expr; + type Output: ValueType; + fn cmp_eq(&self, rhs: Rhs) -> Self::Output; + fn cmp_ne(&self, rhs: Rhs) -> Self::Output; } pub trait HdlPartialOrd: HdlPartialEq { - fn cmp_lt(self, rhs: Rhs) -> Expr; - fn cmp_le(self, rhs: Rhs) -> Expr; - fn cmp_gt(self, rhs: Rhs) -> Expr; - fn cmp_ge(self, rhs: Rhs) -> Expr; + fn cmp_lt(&self, rhs: Rhs) -> Self::Output; + fn cmp_le(&self, rhs: Rhs) -> Self::Output; + fn cmp_gt(&self, rhs: Rhs) -> Self::Output; + fn cmp_ge(&self, rhs: Rhs) -> Self::Output; } pub trait ReduceBits { - type UIntOutput; - type BoolOutput; + type UIntOutput: ValueType>; + type BoolOutput: ValueType; fn reduce_bitand(self) -> Self::UIntOutput; fn reduce_bitor(self) -> Self::UIntOutput; fn reduce_bitxor(self) -> Self::UIntOutput; @@ -699,43 +690,59 @@ pub trait ReduceBits { fn parity_even(self) -> Self::BoolOutput; } -pub trait CastToBits { - fn cast_to_bits(&self) -> Expr; +pub trait CastToBits: ValueType { + type Output: ValueType; + fn cast_to_bits(&self) -> Self::Output; } -impl CastToBits for T { - fn cast_to_bits(&self) -> Expr { +impl CastToBits for Expr { + type Output = Expr; + fn cast_to_bits(&self) -> Self::Output { ops::CastToBits::new(Expr::canonical(self.to_expr())).to_expr() } } -pub trait CastBitsTo { +pub trait CastBitsTo: ValueType>> { + type Output: ValueType; #[track_caller] - fn cast_bits_to(&self, ty: T) -> Expr; + fn cast_bits_to(&self, ty: T) -> Self::Output; } -impl> + ?Sized, Width: Size> CastBitsTo for T { +impl CastBitsTo for Expr> { + type Output = Expr; fn cast_bits_to(&self, ty: ToType) -> Expr { - ops::CastBitsTo::new(Expr::as_dyn_int(self.to_expr()), ty).to_expr() + ops::CastBitsTo::new(Expr::as_dyn_int(*self), ty).to_expr() } } -pub trait CastTo: ToExpr { - fn cast_to(&self, to_type: ToType) -> Expr - where - Self::Type: ExprCastTo, - { - ExprCastTo::cast_to(self.to_expr(), to_type) - } - fn cast_to_static(&self) -> Expr - where - Self::Type: ExprCastTo, - { - ExprCastTo::cast_to(self.to_expr(), ToType::TYPE) +pub trait CastToImpl { + type Output: ValueType; + fn cast_to(this: &Self, to_type: ToType) -> Self::Output; +} + +impl, ToType: Type> CastToImpl for Expr { + type Output = Expr; + fn cast_to(this: &Self, to_type: ToType) -> Self::Output { + ExprCastTo::cast_to(*this, to_type) } } -impl CastTo for T {} +pub trait CastTo: ValueType { + fn cast_to(&self, to_type: ToType) -> >::Output + where + Self: CastToImpl, + { + CastToImpl::cast_to(self, to_type) + } + fn cast_to_static(&self) -> >::Output + where + Self: CastToImpl, + { + CastToImpl::cast_to(self, ToType::TYPE) + } +} + +impl CastTo for T {} #[doc(hidden)] pub fn check_match_expr( @@ -761,7 +768,7 @@ pub fn repeat( let element = element.to_expr(); let canonical_element = Expr::canonical(element); ops::ArrayLiteral::new( - Expr::ty(element), + element.ty(), std::iter::repeat(canonical_element) .take(L::Size::as_usize(len)) .collect(), @@ -769,9 +776,16 @@ pub fn repeat( .to_expr() } -impl ToExpr for PhantomConst { +impl ValueType for PhantomConst { type Type = Self; + type ValueCategory = value_category::ValueCategoryValue; + fn ty(&self) -> Self::Type { + *self + } +} + +impl ToExpr for PhantomConst { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(), @@ -792,3 +806,231 @@ impl ToLiteralBits for Phan Ok(Interned::default()) } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Valueless(T); + +impl Valueless { + pub const fn new(ty: T) -> Self { + Self(ty) + } + pub const fn ty(self) -> T { + self.0 + } +} + +impl Default for Valueless { + fn default() -> Self { + Self(T::TYPE) + } +} + +pub trait ValueType { + type Type: Type; + type ValueCategory: value_category::ValueCategory; + fn ty(&self) -> Self::Type; +} + +trait ToValuelessSealed {} + +#[expect(private_bounds)] +pub trait ToValueless: ValueType + ToValuelessSealed { + fn to_valueless(&self) -> Valueless { + Valueless::new(self.ty()) + } +} + +impl ToValuelessSealed for T {} + +impl ToValueless for T {} + +impl ValueType for Valueless { + type Type = T; + type ValueCategory = value_category::ValueCategoryValueless; + + fn ty(&self) -> Self::Type { + self.0 + } +} + +impl<'a, T: ?Sized + ValueType> ValueType for &'a T { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl<'a, T: ?Sized + ValueType> ValueType for &'a mut T { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl ValueType for Box { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl ValueType for std::sync::Arc { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl ValueType for std::rc::Rc { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl ValueType for Interned { + type Type = T::Type; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + T::ty(self) + } +} + +impl ValueType for Expr { + type Type = T; + type ValueCategory = value_category::ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.__ty + } +} + +trait ToValueWithCategorySealed {} + +#[expect(private_bounds)] +pub trait ToValueWithCategory: ValueType + ToValueWithCategorySealed { + type ToValueWithCategoryOutput: ValueType; + fn to_value_with_category(this: &Self) -> Self::ToValueWithCategoryOutput; + fn into_value_with_category(this: Self) -> Self::ToValueWithCategoryOutput + where + Self: Sized; +} + +pub trait ToValueWithCategoryHelper: + ValueType +{ + type HelperOutput: ValueType; + fn to_value_with_category_helper(this: &Self) -> Self::HelperOutput; + fn into_value_with_category_helper(this: Self) -> Self::HelperOutput + where + Self: Sized; +} + +impl< + T: ?Sized + ToValueWithCategoryHelper + ValueType, + C: value_category::ValueCategory, +> ToValueWithCategorySealed for T +{ +} + +impl< + T: ?Sized + ToValueWithCategoryHelper + ValueType, + C: value_category::ValueCategory, +> ToValueWithCategory for T +{ + type ToValueWithCategoryOutput = T::HelperOutput; + fn to_value_with_category(this: &Self) -> Self::ToValueWithCategoryOutput { + Self::to_value_with_category_helper(this) + } + fn into_value_with_category(this: Self) -> Self::ToValueWithCategoryOutput + where + Self: Sized, + { + Self::into_value_with_category_helper(this) + } +} + +impl> + ToValueWithCategoryHelper for T +{ + type HelperOutput = Expr; + fn to_value_with_category_helper(this: &Self) -> Self::HelperOutput { + this.to_expr() + } + fn into_value_with_category_helper(this: Self) -> Self::HelperOutput + where + Self: Sized, + { + this.to_expr() + } +} + +impl< + T: ?Sized + crate::sim::value::ToSimValue, +> ToValueWithCategoryHelper for T +{ + type HelperOutput = crate::sim::value::SimValue; + fn to_value_with_category_helper(this: &Self) -> Self::HelperOutput { + this.to_sim_value() + } + fn into_value_with_category_helper(this: Self) -> Self::HelperOutput + where + Self: Sized, + { + this.into_sim_value() + } +} + +impl> + ToValueWithCategoryHelper for T +{ + type HelperOutput = Valueless; + fn to_value_with_category_helper(this: &Self) -> Self::HelperOutput { + this.to_valueless() + } + fn into_value_with_category_helper(this: Self) -> Self::HelperOutput + where + Self: Sized, + { + this.to_valueless() + } +} + +impl< + T: ?Sized + + ToSimValueInner< + ValueCategory = value_category::ValueCategoryValue, + Type: Type, + >, + O: ValueType, +> ToValueWithCategoryHelper for T +{ + type HelperOutput = O; + fn to_value_with_category_helper(this: &Self) -> Self::HelperOutput { + T::to_sim_value_inner(this) + } + fn into_value_with_category_helper(this: Self) -> Self::HelperOutput + where + Self: Sized, + { + T::into_sim_value_inner(this) + } +} + +pub trait ToSimValueInner: ValueType { + fn to_sim_value_inner(this: &Self) -> ::SimValue; + fn into_sim_value_inner(this: Self) -> ::SimValue + where + Self: Sized; +} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index b10e3ae8..96482c4c 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -8,16 +8,15 @@ use crate::{ enum_::{Enum, EnumType, EnumVariant}, expr::{ CastBitsTo as _, CastTo, CastToBits as _, Expr, ExprEnum, Flow, HdlPartialEq, - HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits, + HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits, ToValueless, ValueType, + Valueless, target::{ GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, }, + value_category::ValueCategoryExpr, }, - int::{ - Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, - UIntType, UIntValue, - }, + int::{Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, Size, UInt, UIntType}, intern::{Intern, Interned}, phantom_const::{PhantomConst, PhantomConstValue}, reset::{ @@ -39,24 +38,8 @@ use std::{ }, }; -macro_rules! forward_value_to_expr_unary_op_trait { - ( - #[generics($($generics:tt)*)] - #[value($Value:ty)] - $Trait:ident::$method:ident - ) => { - impl<$($generics)*> $Trait for $Value - where - Expr<<$Value as ToExpr>::Type>: $Trait, - { - type Output = ::Type> as $Trait>::Output; - - fn $method(self) -> Self::Output { - $Trait::$method(self.to_expr()) - } - } - }; -} +#[cfg(test)] +mod test_ops_impls; macro_rules! impl_unary_op_trait { ( @@ -107,9 +90,16 @@ impl NotU { } } -impl ToExpr for NotU { +impl ValueType for NotU { type Type = UIntType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.arg.to_valueless().not().ty() + } +} + +impl ToExpr for NotU { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::NotU(NotU { @@ -117,7 +107,7 @@ impl ToExpr for NotU { literal_bits: self.literal_bits, }) .intern(), - __ty: self.arg.__ty, + __ty: self.ty(), __flow: Flow::Source, } } @@ -138,12 +128,6 @@ impl_unary_op_trait! { } } -forward_value_to_expr_unary_op_trait! { - #[generics(Width: Size)] - #[value(UIntValue)] - Not::not -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct NotS { arg: Expr>, @@ -164,9 +148,16 @@ impl NotS { } } -impl ToExpr for NotS { +impl ValueType for NotS { type Type = UIntType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.arg.to_valueless().not().ty() + } +} + +impl ToExpr for NotS { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::NotS(NotS { @@ -174,7 +165,7 @@ impl ToExpr for NotS { literal_bits: self.literal_bits, }) .intern(), - __ty: self.arg.__ty.as_same_width_uint(), + __ty: self.ty(), __flow: Flow::Source, } } @@ -195,12 +186,6 @@ impl_unary_op_trait! { } } -forward_value_to_expr_unary_op_trait! { - #[generics(Width: Size)] - #[value(SIntValue)] - Not::not -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct NotB { arg: Expr, @@ -221,9 +206,16 @@ impl NotB { } } -impl ToExpr for NotB { +impl ValueType for NotB { type Type = Bool; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + Bool + } +} + +impl ToExpr for NotB { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::NotB(NotB { @@ -231,7 +223,7 @@ impl ToExpr for NotB { literal_bits: self.literal_bits, }) .intern(), - __ty: self.arg.__ty, + __ty: self.arg.ty(), __flow: Flow::Source, } } @@ -270,22 +262,21 @@ impl Neg { }); retval } - pub fn ty(self) -> SInt { - SInt::new_dyn( - Expr::ty(self.arg) - .width() - .checked_add(1) - .expect("width too big"), - ) - } pub fn arg(self) -> Expr { self.arg } } -impl ToExpr for Neg { +impl ValueType for Neg { type Type = SInt; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.arg.to_valueless().neg().ty() + } +} + +impl ToExpr for Neg { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::Neg(*self).intern(), @@ -310,12 +301,6 @@ impl_unary_op_trait! { } } -forward_value_to_expr_unary_op_trait! { - #[generics(Width: Size)] - #[value(SIntValue)] - StdNeg::neg -} - macro_rules! impl_binary_op_trait { ( #[generics($($generics:tt)*)] @@ -323,44 +308,17 @@ macro_rules! impl_binary_op_trait { $($body:tt)* } ) => { - impl< - Rhs: ToExpr, - $($generics)* - > $Trait for Expr<$Lhs> - { + impl<$($generics)*> $Trait> for Expr<$Lhs> { type Output = Expr<$Output>; - fn $method(self, rhs: Rhs) -> Self::Output { + fn $method(self, $rhs: Expr<$Rhs>) -> Self::Output { let $lhs = self; - let $rhs = rhs.to_expr(); $($body)* } } }; } -macro_rules! forward_value_to_expr_binary_op_trait { - ( - #[generics($($generics:tt)*)] - #[lhs_value($LhsValue:ty)] - $Trait:ident::$method:ident - ) => { - impl< - Rhs, - $($generics)* - > $Trait for $LhsValue - where - Expr<<$LhsValue as ToExpr>::Type>: $Trait, - { - type Output = ::Type> as $Trait>::Output; - - fn $method(self, rhs: Rhs) -> Self::Output { - $Trait::$method(self.to_expr(), rhs) - } - } - }; -} - fn binary_op_literal_bits( result_ty: ResultTy, lhs: Expr, @@ -412,9 +370,16 @@ macro_rules! binary_op_bitwise { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + $ty + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -461,9 +426,6 @@ macro_rules! binary_op_bitwise { pub fn rhs(self) -> Expr<$ty> { self.rhs } - pub fn ty(self) -> UInt { - UInt::new_dyn(Expr::ty(self.lhs).width().max(Expr::ty(self.rhs).width())) - } } impl ToLiteralBits for $name { @@ -474,9 +436,16 @@ macro_rules! binary_op_bitwise { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = UInt; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().$method(self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -492,12 +461,6 @@ macro_rules! binary_op_bitwise { $name::new(Expr::as_dyn_int(lhs), Expr::as_dyn_int(rhs)).to_expr() } } - - forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value($value)] - $Trait::$method - } }; } @@ -538,15 +501,6 @@ macro_rules! binary_op_add_sub { pub fn rhs(self) -> Expr<$ty> { self.rhs } - pub fn ty(self) -> $ty { - $ty::new_dyn( - Expr::ty(self.lhs) - .width() - .max(Expr::ty(self.rhs).width()) - .checked_add(1) - .expect("width too big"), - ) - } } impl ToLiteralBits for $name { @@ -557,9 +511,16 @@ macro_rules! binary_op_add_sub { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + $Trait::$method(self.lhs.to_valueless(), self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -575,12 +536,6 @@ macro_rules! binary_op_add_sub { $name::new(Expr::as_dyn_int(lhs), Expr::as_dyn_int(rhs)).to_expr() } } - - forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value($value)] - $Trait::$method - } }; } @@ -616,14 +571,6 @@ macro_rules! binary_op_mul { pub fn rhs(self) -> Expr<$ty> { self.rhs } - pub fn ty(self) -> $ty { - $ty::new_dyn( - Expr::ty(self.lhs) - .width() - .checked_add(Expr::ty(self.rhs).width()) - .expect("width too big"), - ) - } } impl ToLiteralBits for $name { @@ -634,9 +581,16 @@ macro_rules! binary_op_mul { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().mul(self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -652,12 +606,6 @@ macro_rules! binary_op_mul { $name::new(Expr::as_dyn_int(lhs), Expr::as_dyn_int(rhs)).to_expr() } } - - forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value($value)] - Mul::mul - } }; } @@ -689,9 +637,6 @@ impl DivU { pub fn rhs(self) -> Expr { self.rhs } - pub fn ty(self) -> UIntType { - Expr::ty(self.lhs) - } } impl ToLiteralBits for DivU { @@ -702,9 +647,16 @@ impl ToLiteralBits for DivU { impl_get_target_none!([LhsWidth: Size] DivU); -impl ToExpr for DivU { +impl ValueType for DivU { type Type = UIntType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().div(self.rhs.to_valueless()).ty() + } +} + +impl ToExpr for DivU { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::DivU(DivU { @@ -726,12 +678,6 @@ impl_binary_op_trait! { } } -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(UIntValue)] - Div::div -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct DivS { lhs: Expr, @@ -757,14 +703,6 @@ impl DivS { pub fn rhs(self) -> Expr { self.rhs } - pub fn ty(self) -> SInt { - SInt::new_dyn( - Expr::ty(self.lhs) - .width() - .checked_add(1) - .expect("width too big"), - ) - } } impl ToLiteralBits for DivS { @@ -775,9 +713,16 @@ impl ToLiteralBits for DivS { impl_get_target_none!([] DivS); -impl ToExpr for DivS { +impl ValueType for DivS { type Type = SInt; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().div(self.rhs.to_valueless()).ty() + } +} + +impl ToExpr for DivS { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::DivS(*self).intern(), @@ -794,12 +739,6 @@ impl_binary_op_trait! { } } -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(SIntValue)] - Div::div -} - macro_rules! binary_op_rem { ($name:ident, $ty:ident, $value:ident) => { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -831,9 +770,6 @@ macro_rules! binary_op_rem { pub fn rhs(self) -> Expr<$ty> { self.rhs } - pub fn ty(self) -> $ty { - $ty::new_dyn(Expr::ty(self.lhs).width().min(Expr::ty(self.rhs).width())) - } } impl ToLiteralBits for $name { @@ -844,9 +780,16 @@ macro_rules! binary_op_rem { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().rem(self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -862,12 +805,6 @@ macro_rules! binary_op_rem { $name::new(Expr::as_dyn_int(lhs), Expr::as_dyn_int(rhs)).to_expr() } } - - forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value($value)] - Rem::rem - } }; } @@ -894,7 +831,7 @@ impl BundleLiteral { for (&field, &field_value) in fields.iter().zip(field_values.iter()) { assert_eq!( field.ty, - Expr::ty(field_value), + field_value.ty(), "field's type doesn't match value's type: field name {:?}", field.name ); @@ -914,9 +851,6 @@ impl BundleLiteral { .ok_or(NotALiteralExpr), } } - pub fn ty(self) -> T { - self.ty - } pub fn field_values(self) -> Interned<[Expr]> { self.field_values } @@ -930,9 +864,16 @@ impl ToLiteralBits for BundleLiteral { impl_get_target_none!([T: BundleType] BundleLiteral); -impl ToExpr for BundleLiteral { +impl ValueType for BundleLiteral { type Type = T; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for BundleLiteral { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::BundleLiteral(BundleLiteral { @@ -968,7 +909,7 @@ impl ArrayLiteral { for &element_value in element_values.iter() { assert_eq!( canonical_element_type, - Expr::ty(element_value), + element_value.ty(), "array's element type doesn't match element value's type", ); if let (Some(literal_bits), Ok(element_bits)) = @@ -997,12 +938,6 @@ impl ArrayLiteral { pub fn is_empty(self) -> bool { self.element_values.is_empty() } - pub fn ty(self) -> ArrayType { - ArrayType::new( - self.element_type, - Len::from_usize(self.element_values.len()), - ) - } pub fn element_values(self) -> Interned<[Expr]> { self.element_values } @@ -1016,9 +951,19 @@ impl ToLiteralBits for ArrayLiteral { impl_get_target_none!([Element: Type, Len: Size] ArrayLiteral); -impl ToExpr for ArrayLiteral { +impl ValueType for ArrayLiteral { type Type = ArrayType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + ArrayType::new( + self.element_type, + Len::from_usize(self.element_values.len()), + ) + } +} + +impl ToExpr for ArrayLiteral { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::ArrayLiteral(ArrayLiteral { @@ -1034,12 +979,22 @@ impl ToExpr for ArrayLiteral { } } -impl, const N: usize> ToExpr for [T; N] +impl, const N: usize> ValueType for [T; N] where ConstUsize: KnownSize, { type Type = Array; + type ValueCategory = T::ValueCategory; + fn ty(&self) -> Self::Type { + StaticType::TYPE + } +} + +impl, const N: usize> ToExpr for [T; N] +where + ConstUsize: KnownSize, +{ fn to_expr(&self) -> Expr { ArrayLiteral::new( T::Type::TYPE, @@ -1049,9 +1004,16 @@ where } } +impl> ValueType for [T] { + type Type = Array; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + ArrayType::new_dyn(StaticType::TYPE, self.len()) + } +} + impl> ToExpr for [T] { - type Type = Array; - fn to_expr(&self) -> Expr { ArrayLiteral::new( T::Type::TYPE, @@ -1061,9 +1023,16 @@ impl> ToExpr for [T] { } } -impl> ToExpr for Vec { +impl> ValueType for Vec { type Type = Array; + type ValueCategory = T::ValueCategory; + fn ty(&self) -> Self::Type { + <[T]>::ty(self) + } +} + +impl> ToExpr for Vec { fn to_expr(&self) -> Expr { <[T]>::to_expr(self) } @@ -1090,7 +1059,7 @@ impl EnumLiteral { assert!(variant_index < variants.len()); assert_eq!( variants[variant_index].ty, - variant_value.map(Expr::ty), + variant_value.map(|v| v.ty()), "variant's type doesn't match value's type: variant name {:?}", variants[variant_index].name ); @@ -1130,9 +1099,6 @@ impl EnumLiteral { }; Self::new_by_index(ty, *variant_index, variant_value) } - pub fn ty(self) -> T { - self.ty - } pub fn variant_index(self) -> usize { self.variant_index } @@ -1152,9 +1118,16 @@ impl ToLiteralBits for EnumLiteral { impl_get_target_none!([T: EnumType] EnumLiteral); -impl ToExpr for EnumLiteral { +impl ValueType for EnumLiteral { type Type = T; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for EnumLiteral { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::EnumLiteral(EnumLiteral { @@ -1199,25 +1172,6 @@ macro_rules! impl_dyn_shl { pub fn rhs(self) -> Expr { self.rhs } - #[track_caller] - pub fn ty(self) -> $ty { - let Some(pow2_rhs_width) = Expr::ty(self.rhs) - .width() - .try_into() - .ok() - .and_then(|v| 2usize.checked_pow(v)) - else { - panic!( - "dynamic left-shift amount's bit-width is too big, try casting the shift \ - amount to a smaller bit-width before shifting" - ); - }; - $ty::new_dyn( - (pow2_rhs_width - 1) - .checked_add(Expr::ty(self.lhs).width()) - .expect("width too big"), - ) - } } impl ToLiteralBits for $name { @@ -1228,9 +1182,17 @@ macro_rules! impl_dyn_shl { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + #[track_caller] + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().shl(self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { #[track_caller] fn to_expr(&self) -> Expr { Expr { @@ -1282,10 +1244,6 @@ macro_rules! impl_dyn_shr { pub fn rhs(self) -> Expr { self.rhs } - #[track_caller] - pub fn ty(self) -> $ty { - Expr::ty(self.lhs) - } } impl ToLiteralBits for $name { @@ -1296,9 +1254,17 @@ macro_rules! impl_dyn_shr { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + #[track_caller] + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().shr(self.rhs.to_valueless()).ty() + } + } + + impl ToExpr for $name { #[track_caller] fn to_expr(&self) -> Expr { Expr { @@ -1308,7 +1274,7 @@ macro_rules! impl_dyn_shr { literal_bits: self.literal_bits, }) .intern(), - __ty: Expr::ty(self.lhs), + __ty: self.ty(), __flow: Flow::Source, } } @@ -1327,12 +1293,8 @@ macro_rules! impl_dyn_shr { impl_dyn_shr!(DynShrU, UIntType, UIntValue); impl_dyn_shr!(DynShrS, SIntType, SIntValue); -fn fixed_shr_width(lhs_width: usize, rhs: usize) -> Option { - Some(lhs_width.saturating_sub(rhs).max(1)) -} - macro_rules! binary_op_fixed_shift { - ($name:ident, $ty:ident, $value:ident, $width_fn:path, $Trait:ident::$method:ident) => { + ($name:ident, $ty:ident, $value:ident, $Trait:ident::$method:ident) => { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct $name { lhs: Expr<$ty>, @@ -1361,11 +1323,6 @@ macro_rules! binary_op_fixed_shift { pub fn rhs(self) -> usize { self.rhs } - pub fn ty(self) -> $ty { - $ty::new_dyn( - $width_fn(Expr::ty(self.lhs).width(), self.rhs).expect("width too big"), - ) - } } impl ToLiteralBits for $name { @@ -1376,9 +1333,16 @@ macro_rules! binary_op_fixed_shift { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $ty; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.lhs.to_valueless().$method(self.rhs).ty() + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -1398,34 +1362,10 @@ macro_rules! binary_op_fixed_shift { }; } -binary_op_fixed_shift!(FixedShlU, UIntType, UIntValue, usize::checked_add, Shl::shl); -binary_op_fixed_shift!(FixedShlS, SIntType, SIntValue, usize::checked_add, Shl::shl); -binary_op_fixed_shift!(FixedShrU, UIntType, UIntValue, fixed_shr_width, Shr::shr); -binary_op_fixed_shift!(FixedShrS, SIntType, SIntValue, fixed_shr_width, Shr::shr); - -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(UIntValue)] - Shl::shl -} - -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(SIntValue)] - Shl::shl -} - -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(UIntValue)] - Shr::shr -} - -forward_value_to_expr_binary_op_trait! { - #[generics(LhsWidth: Size)] - #[lhs_value(SIntValue)] - Shr::shr -} +binary_op_fixed_shift!(FixedShlU, UIntType, UIntValue, Shl::shl); +binary_op_fixed_shift!(FixedShlS, SIntType, SIntValue, Shl::shl); +binary_op_fixed_shift!(FixedShrU, UIntType, UIntValue, Shr::shr); +binary_op_fixed_shift!(FixedShrS, SIntType, SIntValue, Shr::shr); pub trait ExprPartialEq: Type { fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr; @@ -1439,33 +1379,34 @@ pub trait ExprPartialOrd: ExprPartialEq { fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr; } -impl HdlPartialEq for Lhs +impl> HdlPartialEq for Expr where - Lhs::Type: ExprPartialEq, + Lhs: ExprPartialEq, { - fn cmp_eq(self, rhs: Rhs) -> Expr { - ExprPartialEq::cmp_eq(self.to_expr(), rhs.to_expr()) + type Output = Expr; + fn cmp_eq(&self, rhs: R) -> Self::Output { + ExprPartialEq::cmp_eq(*self, rhs.to_expr()) } - fn cmp_ne(self, rhs: Rhs) -> Expr { - ExprPartialEq::cmp_ne(self.to_expr(), rhs.to_expr()) + fn cmp_ne(&self, rhs: R) -> Self::Output { + ExprPartialEq::cmp_ne(*self, rhs.to_expr()) } } -impl HdlPartialOrd for Lhs +impl> HdlPartialOrd for Expr where - Lhs::Type: ExprPartialOrd, + Lhs: ExprPartialOrd, { - fn cmp_lt(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_lt(self.to_expr(), rhs.to_expr()) + fn cmp_lt(&self, rhs: R) -> Self::Output { + ExprPartialOrd::cmp_lt(*self, rhs.to_expr()) } - fn cmp_le(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_le(self.to_expr(), rhs.to_expr()) + fn cmp_le(&self, rhs: R) -> Self::Output { + ExprPartialOrd::cmp_le(*self, rhs.to_expr()) } - fn cmp_gt(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_gt(self.to_expr(), rhs.to_expr()) + fn cmp_gt(&self, rhs: R) -> Self::Output { + ExprPartialOrd::cmp_gt(*self, rhs.to_expr()) } - fn cmp_ge(self, rhs: Rhs) -> Expr { - ExprPartialOrd::cmp_ge(self.to_expr(), rhs.to_expr()) + fn cmp_ge(&self, rhs: R) -> Self::Output { + ExprPartialOrd::cmp_ge(*self, rhs.to_expr()) } } @@ -1515,9 +1456,16 @@ macro_rules! impl_compare_op { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = Bool; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + Bool + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -1633,9 +1581,6 @@ macro_rules! impl_cast_int_op { pub fn arg(self) -> Expr<$from> { self.arg } - pub fn ty(self) -> $to { - self.ty - } } impl ToLiteralBits for $name { @@ -1646,9 +1591,16 @@ macro_rules! impl_cast_int_op { impl_get_target_none!([ToWidth: Size] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $to; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.ty + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name($name { @@ -1681,13 +1633,17 @@ macro_rules! impl_cast_bit_op { impl_cast_bit_op!($name, $from, $(#[dyn] $from_dyn,)? $to); impl $Trait for Expr<$from> { - fn $trait_fn(&self) -> Expr<$to> { + type Output = Expr<$to>; + + fn $trait_fn(&self) -> Self::Output { self.cast_to_static() } } $(impl $Trait for Expr<$from_dyn> { - fn $trait_fn(&self) -> Expr<$to> { + type Output = Expr<$to>; + + fn $trait_fn(&self) -> Self::Output { self.cast_to_static() } })? @@ -1738,9 +1694,16 @@ macro_rules! impl_cast_bit_op { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = $to; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + Self::Type::TYPE + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -1793,7 +1756,9 @@ impl_cast_bit_op!(CastClockToUInt, Clock, UInt<1>, #[dyn] UInt); impl_cast_bit_op!(CastClockToSInt, Clock, SInt<1>, #[dyn] SInt); impl ToReset for Expr { - fn to_reset(&self) -> Expr { + type Output = Expr; + + fn to_reset(&self) -> Self::Output { struct Dispatch; impl ResetTypeDispatch for Dispatch { type Input = Expr; @@ -1934,10 +1899,10 @@ impl fmt::Debug for FieldAccess { impl FieldAccess { #[track_caller] pub fn new_by_index(base: Expr, field_index: usize) -> Self { - let field = Expr::ty(base).fields()[field_index]; + let field = base.ty().fields()[field_index]; let field_type = FieldType::from_canonical(field.ty); let literal_bits = base.to_literal_bits().map(|bits| { - bits[Expr::ty(base).field_offsets()[field_index].bit_width..][..field.ty.bit_width()] + bits[base.ty().field_offsets()[field_index].bit_width..][..field.ty.bit_width()] .intern() }); let target = base.target().map(|base| { @@ -1956,7 +1921,7 @@ impl FieldAccess { } #[track_caller] pub fn new_by_name(base: Expr, name: Interned) -> Self { - let base_ty = Expr::ty(base); + let base_ty = base.ty(); let Some(field_index) = base_ty.name_indexes().get(&name) else { panic!("unknown field {name:?}: in {base_ty:?}"); }; @@ -1991,9 +1956,16 @@ impl ToLiteralBits for FieldAccess { } } -impl ToExpr for FieldAccess { +impl ValueType for FieldAccess { type Type = FieldType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.field_type + } +} + +impl ToExpr for FieldAccess { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::FieldAccess(FieldAccess { @@ -2023,10 +1995,10 @@ pub struct VariantAccess { impl VariantAccess { #[track_caller] pub fn new_by_index(base: Expr, variant_index: usize) -> Self { - let variant = Expr::ty(base).variants()[variant_index]; + let variant = base.ty().variants()[variant_index]; let variant_type = variant.ty.map(VariantType::from_canonical); let literal_bits = base.to_literal_bits().and_then(|bits| { - let discriminant_bit_width = Expr::ty(base).discriminant_bit_width(); + let discriminant_bit_width = base.ty().discriminant_bit_width(); if bits[..discriminant_bit_width] != [variant_index].view_bits::()[..discriminant_bit_width] { @@ -2047,7 +2019,7 @@ impl VariantAccess { } #[track_caller] pub fn new_by_name(base: Expr, name: Interned) -> Self { - let base_ty = Expr::ty(base); + let base_ty = base.ty(); let Some(variant_index) = base_ty.name_indexes().get(&name) else { panic!("unknown variant {name:?}: in {base_ty:?}"); }; @@ -2078,9 +2050,17 @@ impl ToLiteralBits for VariantAccess { impl_get_target_none!([VariantType: Type] VariantAccess); -impl ToExpr for VariantAccess { +impl ValueType for VariantAccess { type Type = VariantType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.variant_type + .unwrap_or_else(|| VariantType::from_canonical(().canonical())) + } +} + +impl ToExpr for VariantAccess { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::VariantAccess(VariantAccess { @@ -2091,9 +2071,7 @@ impl ToExpr for VariantAccess { literal_bits: self.literal_bits, }) .intern(), - __ty: self - .variant_type - .unwrap_or_else(|| VariantType::from_canonical(().canonical())), + __ty: self.ty(), __flow: Flow::Source, } } @@ -2111,7 +2089,7 @@ pub struct ArrayIndex { impl ArrayIndex { #[track_caller] pub fn new(base: Expr, element_index: usize) -> Self { - let base_ty = Expr::ty(base); + let base_ty = base.ty(); assert!(element_index < base_ty.len()); let element_type = ElementType::from_canonical(base_ty.element()); let literal_bits = base.to_literal_bits().map(|bits| { @@ -2159,15 +2137,22 @@ impl GetTarget for ArrayIndex { } } -impl ToExpr for ArrayIndex { +impl ValueType for ArrayIndex { type Type = ElementType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.element_type + } +} + +impl ToExpr for ArrayIndex { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::ArrayIndex(ArrayIndex { base: self.base, element_index: self.element_index, - element_type: Expr::ty(self.base).element(), + element_type: self.base.ty().element(), literal_bits: self.literal_bits, target: self.target, }) @@ -2203,7 +2188,7 @@ pub struct DynArrayIndex { impl DynArrayIndex { #[track_caller] pub fn new(base: Expr, element_index: Expr) -> Self { - let base_ty = Expr::ty(base); + let base_ty = base.ty(); let element_type = ElementType::from_canonical(base_ty.element()); let literal_bits = base .to_literal_bits() @@ -2255,15 +2240,22 @@ impl GetTarget for DynArrayIndex { } } -impl ToExpr for DynArrayIndex { +impl ValueType for DynArrayIndex { type Type = ElementType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.element_type + } +} + +impl ToExpr for DynArrayIndex { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::DynArrayIndex(DynArrayIndex { base: self.base, element_index: self.element_index, - element_type: Expr::ty(self.base).element(), + element_type: self.base.ty().element(), literal_bits: self.literal_bits, target: self.target, }) @@ -2356,7 +2348,7 @@ macro_rules! impl_int_slice { impl $name { pub fn new(base: Expr<$ty>, range: Range) -> Self { assert!( - range.start <= range.end && range.end <= Expr::ty(base).width(), + range.start <= range.end && range.end <= base.ty().width(), "invalid range" ); let literal_bits = base @@ -2385,37 +2377,63 @@ macro_rules! impl_int_slice { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = UInt; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + UInt::new_dyn(self.range().len()) + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), - __ty: UInt::new_dyn(self.range().len()), + __ty: self.ty(), __flow: Flow::Source, } } } + impl> std::ops::Index for Valueless<$ty> { + type Output = Valueless; + + #[track_caller] + fn index(&self, index: I) -> &Self::Output { + let range = self.ty().slice_index_to_range(index); + Interned::into_inner(Valueless::new(UInt::new_dyn(range.len())).intern_sized()) + } + } + impl> ExprIndex for $ty { type Output = UInt; #[track_caller] fn expr_index(this: &Expr, index: I) -> &Expr { let base = Expr::as_dyn_int(*this); - let base_ty = Expr::ty(base); - let range = base_ty.slice_index_to_range(index); + let range = base.ty().slice_index_to_range(index); Interned::into_inner($name::new(base, range).to_expr().intern_sized()) } } + impl std::ops::Index for Valueless<$ty> { + type Output = Valueless; + + #[track_caller] + fn index(&self, index: usize) -> &Self::Output { + assert!(index < self.ty().width()); + &const { Valueless::new(Bool) } + } + } + impl ExprIndex for $ty { type Output = Bool; #[track_caller] fn expr_index(this: &Expr, index: usize) -> &Expr { let base = Expr::as_dyn_int(*this); - let base_ty = Expr::ty(base); + let base_ty = base.ty(); assert!(index < base_ty.width()); Interned::into_inner( $name::new(base, index..(index + 1)) @@ -2457,9 +2475,16 @@ macro_rules! impl_reduce_bits { impl_get_target_none!([] $name); - impl ToExpr for $name { + impl ValueType for $name { type Type = UInt<1>; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + StaticType::TYPE + } + } + + impl ToExpr for $name { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::$name(*self).intern(), @@ -2629,13 +2654,20 @@ impl ToLiteralBits for CastToBits { impl_get_target_none!([] CastToBits); -impl ToExpr for CastToBits { +impl ValueType for CastToBits { type Type = UInt; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + UInt::new_dyn(self.arg.ty().bit_width()) + } +} + +impl ToExpr for CastToBits { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::CastToBits(*self).intern(), - __ty: UInt::new_dyn(Expr::ty(self.arg).bit_width()), + __ty: self.ty(), __flow: Flow::Source, } } @@ -2653,7 +2685,7 @@ impl CastBitsTo { pub fn new(arg: Expr, ty: T) -> Self { let ty_props = ty.canonical().type_properties(); assert!(ty_props.is_castable_from_bits); - assert_eq!(Expr::ty(arg).width(), ty_props.bit_width); + assert_eq!(arg.ty().width(), ty_props.bit_width); Self { arg, ty, @@ -2663,9 +2695,6 @@ impl CastBitsTo { pub fn arg(self) -> Expr { self.arg } - pub fn ty(self) -> T { - self.ty - } } impl ToLiteralBits for CastBitsTo { @@ -2676,9 +2705,16 @@ impl ToLiteralBits for CastBitsTo { impl_get_target_none!([T: Type] CastBitsTo); -impl ToExpr for CastBitsTo { +impl ValueType for CastBitsTo { type Type = T; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for CastBitsTo { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::CastBitsTo(CastBitsTo { @@ -2703,9 +2739,6 @@ impl Uninit { pub fn new(ty: T) -> Self { Self { ty } } - pub fn ty(self) -> T { - self.ty - } } impl ToLiteralBits for Uninit { @@ -2716,9 +2749,16 @@ impl ToLiteralBits for Uninit { impl_get_target_none!([T: Type] Uninit); -impl ToExpr for Uninit { +impl ValueType for Uninit { type Type = T; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for Uninit { fn to_expr(&self) -> Expr { Expr { __enum: ExprEnum::Uninit(Uninit { diff --git a/crates/fayalite/src/expr/ops/test_ops_impls.rs b/crates/fayalite/src/expr/ops/test_ops_impls.rs new file mode 100644 index 00000000..863da419 --- /dev/null +++ b/crates/fayalite/src/expr/ops/test_ops_impls.rs @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{expr::Valueless, prelude::*}; +use std::num::NonZero; + +macro_rules! assert_impls_for { + ( + $([$($args:tt)*])? + $m:ident! {$($rest:tt)*} + ) => { + $m! {$($($args)*)? $($rest)*} + }; + ( + #[kinds()] + $($rest:tt)* + ) => {}; + ( + #[kinds($first_kind:tt $(, $kinds:tt)* $(,)?)] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kind($first_kind)] + $($rest)* + } + assert_impls_for! { + #[kinds($($kinds),*)] + $($rest)* + } + }; + ( + #[type($($ty:tt)*)] + $(#[$($meta:tt)*])* + $([$($args:tt)*])? + $m:ident $($rest:tt)* + ) => { + assert_impls_for! { + $(#[$($meta)*])* + [$($($args)*)? $($ty)*,] + $m $($rest)* + } + }; + ( + #[kind((int<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds((uint<$lt, $Width>), (sint<$lt, $Width>))] + $($rest)* + } + }; + ( + #[kind((int_value<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds((uint_value<$lt, $Width>), (sint_value<$lt, $Width>))] + $($rest)* + } + }; + ( + #[kind((uint_nz<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + (NonZero), + NonZeroU_N, + (uint<$lt, $Width>), + )] + $($rest)* + } + }; + ( + #[kind((sint_nz<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + (NonZero), + NonZeroI_N, + (sint<$lt, $Width>), + )] + $($rest)* + } + }; + ( + #[kind((uint<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + usize, + u_N, + (UIntValue<$Width: Size>), + (&$lt UIntValue<$Width: Size>), + (SimValue>), + (&$lt SimValue>), + (Expr>), + (Valueless>), + )] + $($rest)* + } + }; + ( + #[kind((sint<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + isize, + i_N, + (SIntValue<$Width: Size>), + (&$lt SIntValue<$Width: Size>), + (SimValue>), + (&$lt SimValue>), + (Expr>), + (Valueless>), + )] + $($rest)* + } + }; + ( + #[kind((uint_value<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + (UIntValue<$Width: Size>), + (&$lt UIntValue<$Width: Size>), + (SimValue>), + (&$lt SimValue>), + (Expr>), + (Valueless>), + )] + $($rest)* + } + }; + ( + #[kind((sint_value<$lt:lifetime, $Width:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + (SIntValue<$Width: Size>), + (&$lt SIntValue<$Width: Size>), + (SimValue>), + (&$lt SimValue>), + (Expr>), + (Valueless>), + )] + $($rest)* + } + }; + ( + #[kind((Bool<$lt:lifetime>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds( + bool, + (SimValue), + (&$lt SimValue), + (Expr), + (Valueless), + )] + $($rest)* + } + }; + ( + #[kind(u_N)] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds(u8, u16, u32, u64, u128)] + $($rest)* + } + }; + ( + #[kind(i_N)] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds(i8, i16, i32, i64, i128)] + $($rest)* + } + }; + ( + #[kind(NonZeroU_N)] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds((NonZero), (NonZero), (NonZero), (NonZero), (NonZero))] + $($rest)* + } + }; + ( + #[kind(NonZeroI_N)] + $($rest:tt)* + ) => { + assert_impls_for! { + #[kinds((NonZero), (NonZero), (NonZero), (NonZero), (NonZero))] + $($rest)* + } + }; + ( + #[kind(($wrapper:ident<$Ty:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([][] $wrapper<$Ty>)] + $($rest)* + } + }; + ( + #[kind((&$lt:lifetime $wrapper:ident<$Ty:ident>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([$lt,][] &$lt $wrapper<$Ty>)] + $($rest)* + } + }; + ( + #[kind(($wrapper:ident<$Width:ident: Size>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([][$Width: Size,] $wrapper<$Width>)] + $($rest)* + } + }; + ( + #[kind(($wrapper:ident<$ty:ident<$Width:ident: Size>>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([][$Width: Size,] $wrapper<$ty<$Width>>)] + $($rest)* + } + }; + ( + #[kind((&$lt:lifetime $wrapper:ident<$Width:ident: Size>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([$lt,][$Width: Size,] &$lt $wrapper<$Width>)] + $($rest)* + } + }; + ( + #[kind((&$lt:lifetime $wrapper:ident<$ty:ident<$Width:ident: Size>>))] + $($rest:tt)* + ) => { + assert_impls_for! { + #[type([$lt,][$Width: Size,] &$lt $wrapper<$ty<$Width>>)] + $($rest)* + } + }; + (#[kind(usize)] $($rest:tt)*) => {assert_impls_for! { #[type([][] usize)] $($rest)* }}; + (#[kind(isize)] $($rest:tt)*) => {assert_impls_for! { #[type([][] isize)] $($rest)* }}; + (#[kind(bool)] $($rest:tt)*) => {assert_impls_for! { #[type([][] bool)] $($rest)* }}; + (#[kind(u8)] $($rest:tt)*) => {assert_impls_for! { #[type([][] u8)] $($rest)* }}; + (#[kind(u16)] $($rest:tt)*) => {assert_impls_for! { #[type([][] u16)] $($rest)* }}; + (#[kind(u32)] $($rest:tt)*) => {assert_impls_for! { #[type([][] u32)] $($rest)* }}; + (#[kind(u64)] $($rest:tt)*) => {assert_impls_for! { #[type([][] u64)] $($rest)* }}; + (#[kind(u128)] $($rest:tt)*) => {assert_impls_for! { #[type([][] u128)] $($rest)* }}; + (#[kind(i8)] $($rest:tt)*) => {assert_impls_for! { #[type([][] i8)] $($rest)* }}; + (#[kind(i16)] $($rest:tt)*) => {assert_impls_for! { #[type([][] i16)] $($rest)* }}; + (#[kind(i32)] $($rest:tt)*) => {assert_impls_for! { #[type([][] i32)] $($rest)* }}; + (#[kind(i64)] $($rest:tt)*) => {assert_impls_for! { #[type([][] i64)] $($rest)* }}; + (#[kind(i128)] $($rest:tt)*) => {assert_impls_for! { #[type([][] i128)] $($rest)* }}; +} + +macro_rules! assert_neg_impls { + ([$($Lifetimes:tt)*][$($Bounds:tt)*] $ty:ty,) => { + const _: () = { + fn _check_neg_impl<$($Lifetimes)*$($Bounds)*>(v: $ty) -> impl ValueType { + std::ops::Neg::neg(v) + } + }; + }; +} + +assert_impls_for! { + #[kinds((sint<'a, Width>))] + assert_neg_impls! {} +} + +macro_rules! assert_not_impls { + ([$($Lifetimes:tt)*][$($Bounds:tt)*] $ty:ty,) => { + const _: () = { + fn _check_not_impl<$($Lifetimes)*$($Bounds)*>(v: $ty) -> impl ValueType { + std::ops::Not::not(v) + } + }; + }; +} + +assert_impls_for! { + #[kinds((int<'a, Width>), (Bool<'a>))] + assert_not_impls! {} +} + +macro_rules! assert_simple_bin_op_impls { + ([$($LLifetimes:tt)*][$($LBounds:tt)*] $L:ty, [$($RLifetimes:tt)*][$($RBounds:tt)*] $R:ty, $Trait:ident::$f:ident) => { + const _: () = { + fn _check_simple_bin_op_impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*>(l: $L, r: $R) -> impl ValueType { + std::ops::$Trait::$f(l, r) + } + }; + }; + ($LLifetimes:tt $LBounds:tt $L:ty, $RLifetimes:tt $RBounds:tt $R:ty, $FirstTrait:ident::$first_f:ident, $($rest:tt)*) => { + assert_simple_bin_op_impls! { + $LLifetimes $LBounds $L, $RLifetimes $RBounds $R, $FirstTrait::$first_f + } + assert_simple_bin_op_impls! { + $LLifetimes $LBounds $L, $RLifetimes $RBounds $R, $($rest)* + } + }; +} + +assert_impls_for! { + #[kinds((uint_value<'l, L>))] + #[kinds((uint_nz<'r, R>))] + assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor} +} + +assert_impls_for! { + #[kinds((uint_nz<'l, L>))] + #[kinds((uint_value<'r, R>))] + assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor, Shl::shl, Shr::shr} +} + +assert_impls_for! { + #[kinds((sint_value<'l, L>))] + #[kinds((sint_nz<'r, R>))] + assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor} +} + +assert_impls_for! { + #[kinds((sint_nz<'l, L>))] + #[kinds((sint_value<'r, R>))] + assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor, Shl::shl, Shr::shr} +} + +assert_impls_for! { + #[kinds((uint_value<'l, L>))] + assert_simple_bin_op_impls! {[][] usize, Shl::shl, Shr::shr} +} + +assert_impls_for! { + #[kinds((sint_value<'l, L>))] + assert_simple_bin_op_impls! {[][] usize, Shl::shl, Shr::shr} +} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index c8c55e93..95d8e0f5 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -3,7 +3,7 @@ use crate::{ array::Array, bundle::{Bundle, BundleField}, - expr::{Expr, Flow, ToExpr}, + expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr}, intern::{Intern, Interned}, memory::{DynPortType, MemPort}, module::{Instance, ModuleIO, TargetName}, @@ -196,9 +196,18 @@ macro_rules! impl_target_base { } } - impl ToExpr for $TargetBase { + impl ValueType for $TargetBase { type Type = CanonicalType; + type ValueCategory = ValueCategoryExpr; + fn ty(&self) -> Self::Type { + match self { + $(Self::$Variant(v) => v.ty().canonical(),)* + } + } + } + + impl ToExpr for $TargetBase { fn to_expr(&self) -> Expr { match self { $(Self::$Variant(v) => Expr::canonical(v.to_expr()),)* diff --git a/crates/fayalite/src/expr/value_category.rs b/crates/fayalite/src/expr/value_category.rs new file mode 100644 index 00000000..9909f68d --- /dev/null +++ b/crates/fayalite/src/expr/value_category.rs @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{expr::ValueType, ty::Type}; + +trait ValueCategorySealed {} + +#[expect(private_bounds)] +pub trait ValueCategory: + ValueCategorySealed + + Copy + + Ord + + Default + + std::fmt::Debug + + std::hash::Hash + + 'static + + Send + + Sync +{ + type DispatchOutput>: ValueType; + #[track_caller] + fn dispatch>( + dispatch: D, + ) -> Self::DispatchOutput; + #[track_caller] + fn dispatch_enum>( + dispatch: D, + ) -> ValueCategoryDispatchOutputEnum; +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)] +pub struct ValueCategoryValue; + +impl ValueCategorySealed for ValueCategoryValue {} + +impl ValueCategory for ValueCategoryValue { + type DispatchOutput> = D::Value; + + #[track_caller] + fn dispatch>( + dispatch: D, + ) -> Self::DispatchOutput { + dispatch.dispatch_value() + } + + #[track_caller] + fn dispatch_enum>( + dispatch: D, + ) -> ValueCategoryDispatchOutputEnum { + ValueCategoryDispatchOutputEnum::Value(dispatch.dispatch_value()) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)] +pub struct ValueCategorySimValue; + +impl ValueCategorySealed for ValueCategorySimValue {} + +impl ValueCategory for ValueCategorySimValue { + type DispatchOutput> = D::SimValue; + + #[track_caller] + fn dispatch>( + dispatch: D, + ) -> Self::DispatchOutput { + dispatch.dispatch_sim_value() + } + + #[track_caller] + fn dispatch_enum>( + dispatch: D, + ) -> ValueCategoryDispatchOutputEnum { + ValueCategoryDispatchOutputEnum::SimValue(dispatch.dispatch_sim_value()) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)] +pub struct ValueCategoryExpr; + +impl ValueCategorySealed for ValueCategoryExpr {} + +impl ValueCategory for ValueCategoryExpr { + type DispatchOutput> = D::Expr; + + #[track_caller] + fn dispatch>( + dispatch: D, + ) -> Self::DispatchOutput { + dispatch.dispatch_expr() + } + + #[track_caller] + fn dispatch_enum>( + dispatch: D, + ) -> ValueCategoryDispatchOutputEnum { + ValueCategoryDispatchOutputEnum::Expr(dispatch.dispatch_expr()) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)] +pub struct ValueCategoryValueless; + +impl ValueCategorySealed for ValueCategoryValueless {} + +impl ValueCategory for ValueCategoryValueless { + type DispatchOutput> = D::Valueless; + + #[track_caller] + fn dispatch>( + dispatch: D, + ) -> Self::DispatchOutput { + dispatch.dispatch_valueless() + } + + #[track_caller] + fn dispatch_enum>( + dispatch: D, + ) -> ValueCategoryDispatchOutputEnum { + ValueCategoryDispatchOutputEnum::Valueless(dispatch.dispatch_valueless()) + } +} + +pub trait ValueCategoryIsValue: ValueCategoryIsValueOrSimValue {} + +impl ValueCategoryIsValue for ValueCategoryValue {} + +pub trait ValueCategoryIsValueOrSimValue: ValueCategoryIsValueSimValueOrExpr {} + +impl ValueCategoryIsValueOrSimValue for ValueCategoryValue {} +impl ValueCategoryIsValueOrSimValue for ValueCategorySimValue {} + +pub trait ValueCategoryIsValueSimValueOrExpr: ValueCategoryIsValueSimValueExprOrValueless {} + +impl ValueCategoryIsValueSimValueOrExpr for ValueCategoryValue {} +impl ValueCategoryIsValueSimValueOrExpr for ValueCategorySimValue {} +impl ValueCategoryIsValueSimValueOrExpr for ValueCategoryExpr {} + +pub trait ValueCategoryIsValueSimValueExprOrValueless: ValueCategory {} + +impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryValue {} +impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategorySimValue {} +impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryExpr {} +impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryValueless {} + +pub trait ValueCategoryIsValueless: ValueCategoryIsExprOrValueless {} + +impl ValueCategoryIsValueless for ValueCategoryValueless {} + +pub trait ValueCategoryIsExprOrValueless: ValueCategoryIsValueSimValueExprOrValueless {} + +impl ValueCategoryIsExprOrValueless for ValueCategoryExpr {} +impl ValueCategoryIsExprOrValueless for ValueCategoryValueless {} + +pub trait ValueCategoryIsSimValueExprOrValueless: + ValueCategoryIsValueSimValueExprOrValueless +{ +} + +impl ValueCategoryIsSimValueExprOrValueless for ValueCategorySimValue {} +impl ValueCategoryIsSimValueExprOrValueless for ValueCategoryExpr {} +impl ValueCategoryIsSimValueExprOrValueless for ValueCategoryValueless {} + +trait ValueCategoryCommonSealed {} + +pub trait ValueCategoryCommon< + T: ValueCategoryCommonSealed + + Copy + + Ord + + Default + + std::fmt::Debug + + std::hash::Hash + + 'static + + Send + + Sync, +>: ValueCategory +{ + type Common: ValueCategory; +} + +macro_rules! impl_value_category_common { + ($($T:ident),* $(,)?) => { + impl_value_category_common!([$($T,)*]); + }; + ([$($A:ident,)?]) => {}; + ([$FirstT:ident, $($T:ident,)+]) => { + impl_value_category_common!([$($T,)*]); + + impl<$FirstT: ValueCategory, $($T: ValueCategory),*> ValueCategoryCommonSealed for ($FirstT, $($T),*) {} + + impl ValueCategoryCommon<($FirstT, $($T),*)> for This + where + $FirstT: ValueCategory, + $($T: ValueCategory,)* + This: ValueCategoryCommon<($FirstT,), Common: ValueCategoryCommon<($($T,)*)>>, + { + type Common = <>::Common as ValueCategoryCommon<($($T,)*)>>::Common; + } + }; +} + +impl_value_category_common!(T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0); + +impl ValueCategoryCommonSealed for (T,) {} + +impl ValueCategoryCommonSealed for () {} + +impl ValueCategoryCommon<()> for T { + type Common = T; +} + +impl ValueCategoryCommon<(ValueCategoryValue,)> for T { + type Common = ValueCategoryValue; +} + +impl ValueCategoryCommon<(ValueCategorySimValue,)> for T { + type Common = ValueCategorySimValue; +} + +impl ValueCategoryCommon<(ValueCategoryExpr,)> for T { + type Common = ValueCategoryExpr; +} + +impl ValueCategoryCommon<(ValueCategoryValueless,)> + for T +{ + type Common = ValueCategoryValueless; +} + +pub trait ValueCategoryDispatch: Sized { + type Type: Type; + type InputValueCategory: ValueCategory; + type Value: ValueType; + type SimValue: ValueType; + type Expr: ValueType; + type Valueless: ValueType; + fn dispatch_value(self) -> Self::Value + where + Self: ValueCategoryDispatch; + fn dispatch_sim_value(self) -> Self::SimValue + where + Self: ValueCategoryDispatch; + fn dispatch_expr(self) -> Self::Expr + where + Self: ValueCategoryDispatch; + fn dispatch_valueless(self) -> Self::Valueless + where + Self: ValueCategoryDispatch; + fn dispatch(self) -> ::DispatchOutput { + Self::InputValueCategory::dispatch(self) + } + fn dispatch_enum(self) -> ValueCategoryDispatchOutputEnum { + Self::InputValueCategory::dispatch_enum(self) + } +} + +pub enum ValueCategoryDispatchOutputEnum { + Value(T::Value), + SimValue(T::SimValue), + Expr(T::Expr), + Valueless(T::Valueless), +} + +impl ValueCategoryDispatchOutputEnum { + pub fn try_into_value(self) -> Result { + if let Self::Value(v) = self { + Ok(v) + } else { + Err(self) + } + } + pub fn try_into_sim_value(self) -> Result { + if let Self::SimValue(v) = self { + Ok(v) + } else { + Err(self) + } + } + pub fn try_into_expr(self) -> Result { + if let Self::Expr(v) = self { + Ok(v) + } else { + Err(self) + } + } + pub fn try_into_valueless(self) -> Result { + if let Self::Valueless(v) = self { + Ok(v) + } else { + Err(self) + } + } + #[track_caller] + #[cold] + fn unwrap_invalid(self, expected_kind: &'static str) -> ! { + match self { + Self::Value(_) => panic!("expected {expected_kind}, got Value"), + Self::SimValue(_) => panic!("expected {expected_kind}, got SimValue"), + Self::Expr(_) => panic!("expected {expected_kind}, got Expr"), + Self::Valueless(_) => panic!("expected {expected_kind}, got Valueless"), + } + } + #[track_caller] + pub fn into_value_unwrap(self) -> T::Value { + let Self::Value(v) = self else { + self.unwrap_invalid("Value"); + }; + v + } + #[track_caller] + pub fn into_sim_value_unwrap(self) -> T::SimValue { + let Self::SimValue(v) = self else { + self.unwrap_invalid("SimValue"); + }; + v + } + #[track_caller] + pub fn into_expr_unwrap(self) -> T::Expr { + let Self::Expr(v) = self else { + self.unwrap_invalid("Expr"); + }; + v + } + #[track_caller] + pub fn into_valueless_unwrap(self) -> T::Valueless { + let Self::Valueless(v) = self else { + self.unwrap_invalid("Valueless"); + }; + v + } + pub fn ty(&self) -> T::Type { + match self { + Self::Value(v) => v.ty(), + Self::SimValue(v) => v.ty(), + Self::Expr(v) => v.ty(), + Self::Valueless(v) => v.ty(), + } + } +} diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 59fbec7f..88b97ac5 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -877,7 +877,7 @@ impl<'a> Exporter<'a> { definitions: &RcDefinitions, const_ty: bool, ) -> Result { - let from_ty = Expr::ty(value); + let from_ty = value.ty(); let mut value = self.expr(Expr::canonical(value), definitions, const_ty)?; if from_ty.width().checked_add(1) == Some(to_ty.width()) && !FromTy::Signed::VALUE @@ -926,7 +926,7 @@ impl<'a> Exporter<'a> { definitions: &RcDefinitions, const_ty: bool, ) -> Result { - let base_width = Expr::ty(base).width(); + let base_width = base.ty().width(); let base = self.expr(Expr::canonical(base), definitions, const_ty)?; if range.is_empty() { Ok(format!("tail({base}, {base_width})")) @@ -1653,7 +1653,7 @@ impl<'a> Exporter<'a> { let value_str = self.expr(expr.arg(), definitions, const_ty)?; self.expr_cast_to_bits( value_str, - Expr::ty(expr.arg()), + expr.arg().ty(), definitions, Indent { indent_depth: &Cell::new(0), @@ -1776,7 +1776,7 @@ impl<'a> Exporter<'a> { let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty)?; let name = self .type_state - .get_bundle_field(Expr::ty(expr.base()), expr.field_name())?; + .get_bundle_field(expr.base().ty(), expr.field_name())?; write!(out, ".{name}").unwrap(); Ok(out) } @@ -2101,12 +2101,12 @@ impl<'a> Exporter<'a> { rhs, source_location, }) => { - if Expr::ty(lhs) != Expr::ty(rhs) { + if lhs.ty() != rhs.ty() { writeln!( body, "{indent}; connect different types:\n{indent}; lhs: {:?}\n{indent}; rhs: {:?}", - Expr::ty(lhs), - Expr::ty(rhs), + lhs.ty(), + rhs.ty(), ) .unwrap(); } @@ -2200,7 +2200,7 @@ impl<'a> Exporter<'a> { FileInfo::new(source_location), ) .unwrap(); - let enum_ty = Expr::ty(expr); + let enum_ty = expr.ty(); let match_arms_indent = indent.push(); for ((variant_index, variant), match_arm_block) in enum_ty.variants().iter().enumerate().zip(blocks) diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index 7fa77ce4..d897d5ba 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -4,8 +4,10 @@ use crate::{ array::ArrayType, expr::{ - Expr, NotALiteralExpr, ToExpr, ToLiteralBits, + Expr, HdlPartialEq, HdlPartialOrd, NotALiteralExpr, ToExpr, ToLiteralBits, ToSimValueInner, + ToValueless, ValueType, Valueless, target::{GetTarget, Target}, + value_category::ValueCategoryValue, }, hdl, intern::{Intern, Interned, Memoize}, @@ -530,6 +532,23 @@ fn deserialize_int_value<'de, D: Deserializer<'de>>( }) } +macro_rules! impl_valueless_op_forward { + ( + #[forward_to = $ForwardTrait:path] + impl<$($G:ident: $Bound:path),*> $TraitPath:ident$(::$TraitPathRest:ident)+<$($Rhs:ty)?> for $SelfTy:ty { + $($(type $Output:ident;)? + use $forward_fn:path as $fn:ident($self:ident $(, $rhs:ident)?);)? + } + ) => { + impl<$($G: $Bound),*> $TraitPath$(::$TraitPathRest)+<$($Rhs)?> for $SelfTy { + $($(type $Output = <$SelfTy as $ForwardTrait>::$Output;)? + fn $fn($self $(, $rhs: $Rhs)?) $(-> Self::$Output)? { + $forward_fn($self $(, $rhs)?) + })? + } + }; +} + macro_rules! impl_int { ($pretty_name:ident, $name:ident, $generic_name:ident, $value:ident, $SIGNED:literal) => { #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -582,6 +601,176 @@ macro_rules! impl_int { } } + impl>> + std::ops::Add for Valueless<$name> + { + type Output = Valueless<$name>; + + fn add(self, rhs: Rhs) -> Self::Output { + Valueless::new($name::new_dyn( + self.ty() + .width() + .max(rhs.ty().width()) + .checked_add(1) + .expect("width too big"), + )) + } + } + + impl_valueless_op_forward! { + #[forward_to = std::ops::Add] + impl>> + std::ops::Sub for Valueless<$name> + { + type Output; + + use std::ops::Add::::add as sub(self, rhs); + } + } + + impl>> + std::ops::BitOr for Valueless<$name> + { + type Output = Valueless; + + fn bitor(self, rhs: Rhs) -> Self::Output { + Valueless::new(UInt::new_dyn(self.ty().width().max(rhs.ty().width()))) + } + } + + impl_valueless_op_forward! { + #[forward_to = std::ops::BitOr] + impl>> + std::ops::BitAnd for Valueless<$name> + { + type Output; + + use std::ops::BitOr::::bitor as bitand(self, rhs); + } + } + + impl_valueless_op_forward! { + #[forward_to = std::ops::BitOr] + impl>> + std::ops::BitXor for Valueless<$name> + { + type Output; + + use std::ops::BitOr::::bitor as bitxor(self, rhs); + } + } + + impl std::ops::Not for Valueless<$name> { + type Output = Valueless>; + + fn not(self) -> Self::Output { + Valueless::new(self.ty().as_same_width_uint()) + } + } + + impl std::ops::Not for $value { + type Output = UIntValue; + + fn not(mut self) -> Self::Output { + // modifies in-place despite using `Not::not` + let _ = Not::not(self.bits_mut()); + UIntValue::new(self.into_bits()) + } + } + + impl std::ops::Not for &'_ $value { + type Output = UIntValue; + + fn not(self) -> Self::Output { + $value::not(self.clone()) + } + } + + impl>> + std::ops::Mul for Valueless<$name> + { + type Output = Valueless<$name>; + + fn mul(self, rhs: Rhs) -> Self::Output { + Valueless::new($name::new_dyn( + self.ty() + .width() + .checked_add(rhs.ty().width()) + .expect("width too big"), + )) + } + } + + impl>> + std::ops::Rem for Valueless<$name> + { + type Output = Valueless<$name>; + + fn rem(self, rhs: Rhs) -> Self::Output { + Valueless::new($name::new_dyn(self.ty().width().min(rhs.ty().width()))) + } + } + + impl std::ops::Shl>> + for Valueless<$name> + { + type Output = Valueless<$name>; + + #[track_caller] + fn shl(self, rhs: Valueless>) -> Self::Output { + let Some(pow2_rhs_width) = rhs + .ty() + .width() + .try_into() + .ok() + .and_then(|v| 2usize.checked_pow(v)) + else { + panic!( + "dynamic left-shift amount's bit-width is too big, try casting the shift \ + amount to a smaller bit-width before shifting" + ); + }; + Valueless::new($name::new_dyn( + (pow2_rhs_width - 1) + .checked_add(self.ty().width()) + .expect("width too big"), + )) + } + } + + impl std::ops::Shr>> + for Valueless<$name> + { + type Output = Valueless<$name>; + + fn shr(self, _rhs: Valueless>) -> Self::Output { + self + } + } + + impl std::ops::Shl for Valueless<$name> { + type Output = Valueless<$name>; + + fn shl(self, rhs: usize) -> Self::Output { + Valueless::new($name::new_dyn( + self.ty().width().checked_add(rhs).expect("width too big"), + )) + } + } + + impl std::ops::Shr for Valueless<$name> { + type Output = Valueless<$name>; + + fn shr(self, rhs: usize) -> Self::Output { + let width = self.ty().width().saturating_sub(rhs); + Valueless::new($name::new_dyn(if $SIGNED && width == 0 { + 1 + } else { + width + })) + } + } + impl sealed::BoolOrIntTypeSealed for $name {} impl BoolOrIntType for $name { @@ -861,11 +1050,6 @@ macro_rules! impl_int { pub fn into_bits(self) -> Arc { self.bits } - pub fn ty(&self) -> $name { - $name { - width: Width::from_usize(self.width()), - } - } pub fn as_dyn_int(self) -> $value { $value { bits: self.bits, @@ -878,6 +1062,74 @@ macro_rules! impl_int { pub fn bits_mut(&mut self) -> &mut BitSlice { Arc::::make_mut(&mut self.bits) } + pub fn hdl_cmp(&self, other: &$value) -> std::cmp::Ordering { + self.to_bigint().cmp(&other.to_bigint()) + } + } + + impl ValueType for $value { + type Type = $name; + type ValueCategory = ValueCategoryValue; + + fn ty(&self) -> Self::Type { + $name { + width: Width::from_usize(self.width()), + } + } + } + + impl<'r, L: Size, R: Size> HdlPartialEq<&'r $value> for $value { + type Output = bool; + fn cmp_eq(&self, rhs: &'r $value) -> Self::Output { + if self.width() == rhs.width() { + self.bits() == rhs.bits() + } else { + self.to_bigint() == rhs.to_bigint() + } + } + fn cmp_ne(&self, rhs: &'r $value) -> Self::Output { + !self.cmp_eq(rhs) + } + } + + impl<'r, L: Size, R: Size> HdlPartialOrd<&'r $value> for $value { + fn cmp_lt(&self, rhs: &'r $value) -> Self::Output { + self.hdl_cmp(rhs).is_lt() + } + fn cmp_le(&self, rhs: &'r $value) -> Self::Output { + self.hdl_cmp(rhs).is_le() + } + fn cmp_gt(&self, rhs: &'r $value) -> Self::Output { + self.hdl_cmp(rhs).is_gt() + } + fn cmp_ge(&self, rhs: &'r $value) -> Self::Output { + self.hdl_cmp(rhs).is_ge() + } + } + + impl HdlPartialEq<$value> for $value { + type Output = bool; + fn cmp_eq(&self, rhs: $value) -> Self::Output { + self.cmp_eq(&rhs) + } + fn cmp_ne(&self, rhs: $value) -> Self::Output { + self.cmp_ne(&rhs) + } + } + + impl HdlPartialOrd<$value> for $value { + fn cmp_lt(&self, rhs: $value) -> Self::Output { + self.cmp_lt(&rhs) + } + fn cmp_le(&self, rhs: $value) -> Self::Output { + self.cmp_le(&rhs) + } + fn cmp_gt(&self, rhs: $value) -> Self::Output { + self.cmp_gt(&rhs) + } + fn cmp_ge(&self, rhs: $value) -> Self::Output { + self.cmp_ge(&rhs) + } } impl ToLiteralBits for $value { @@ -923,6 +1175,17 @@ macro_rules! impl_int { Arc::make_mut(&mut self.bits) } } + + impl<'l, 'r, L: Size, R: Size> std::ops::Add<&'r $value> for &'l $value { + type Output = $value; + + fn add(self, rhs: &'r $value) -> Self::Output { + self.to_valueless() + .add(rhs.to_valueless()) + .ty() + .value_from_bigint_wrapping(&(self.to_bigint() + rhs.to_bigint())) + } + } }; } @@ -1015,11 +1278,58 @@ impl SInt { } } -macro_rules! impl_prim_int { +impl>> std::ops::Div + for Valueless> +{ + type Output = Self; + + fn div(self, _rhs: Rhs) -> Self::Output { + self + } +} + +impl>> std::ops::Div + for Valueless> +{ + type Output = Valueless; + + fn div(self, _rhs: Rhs) -> Self::Output { + Valueless::new(SInt::new_dyn( + self.ty().width().checked_add(1).expect("width too big"), + )) + } +} + +impl std::ops::Neg for Valueless> { + type Output = Valueless; + fn neg(self) -> Self::Output { + Valueless::new(SInt::new_dyn( + self.ty().width().checked_add(1).expect("width too big"), + )) + } +} + +impl std::ops::Neg for SIntValue { + type Output = SIntValue; + fn neg(self) -> Self::Output { + -&self + } +} + +impl std::ops::Neg for &'_ SIntValue { + type Output = SIntValue; + fn neg(self) -> Self::Output { + let ty = self.to_valueless().neg().ty(); + ty.from_bigint_wrapping(&-self.to_bigint()) + } +} + +macro_rules! impl_prim_int_to_expr { ( $(#[$meta:meta])* $prim_int:ident, $ty:ty ) => { + $(#[$meta])* impl From<$prim_int> for <$ty as BoolOrIntType>::Value { fn from(v: $prim_int) -> Self { <$ty>::le_bytes_to_value_wrapping( @@ -1028,15 +1338,32 @@ macro_rules! impl_prim_int { ) } } + $(#[$meta])* impl From> for <$ty as BoolOrIntType>::Value { fn from(v: NonZero<$prim_int>) -> Self { v.get().into() } } $(#[$meta])* - impl ToExpr for $prim_int { + impl ToSimValueInner for $prim_int { + fn to_sim_value_inner(this: &Self) -> ::SimValue { + Self::into_sim_value_inner(*this) + } + fn into_sim_value_inner(this: Self) -> ::SimValue { + this.into() + } + } + $(#[$meta])* + impl ValueType for $prim_int { type Type = $ty; + type ValueCategory = ValueCategoryValue; + fn ty(&self) -> Self::Type { + StaticType::TYPE + } + } + $(#[$meta])* + impl ToExpr for $prim_int { fn to_expr(&self) -> Expr { <$ty>::le_bytes_to_expr_wrapping( &self.to_le_bytes(), @@ -1045,9 +1372,25 @@ macro_rules! impl_prim_int { } } $(#[$meta])* - impl ToExpr for NonZero<$prim_int> { + impl ToSimValueInner for NonZero<$prim_int> { + fn to_sim_value_inner(this: &Self) -> ::SimValue { + Self::into_sim_value_inner(*this) + } + fn into_sim_value_inner(this: Self) -> ::SimValue { + this.into() + } + } + $(#[$meta])* + impl ValueType for NonZero<$prim_int> { type Type = $ty; + type ValueCategory = ValueCategoryValue; + fn ty(&self) -> Self::Type { + StaticType::TYPE + } + } + $(#[$meta])* + impl ToExpr for NonZero<$prim_int> { fn to_expr(&self) -> Expr { self.get().to_expr() } @@ -1055,25 +1398,203 @@ macro_rules! impl_prim_int { }; } -impl_prim_int!(u8, UInt<8>); -impl_prim_int!(u16, UInt<16>); -impl_prim_int!(u32, UInt<32>); -impl_prim_int!(u64, UInt<64>); -impl_prim_int!(u128, UInt<128>); -impl_prim_int!(i8, SInt<8>); -impl_prim_int!(i16, SInt<16>); -impl_prim_int!(i32, SInt<32>); -impl_prim_int!(i64, SInt<64>); -impl_prim_int!(i128, SInt<128>); +macro_rules! impl_for_all_prim_uints { + ( + #[size =, $(rest:tt)*] + $m:ident!() + ) => { + impl_for_all_prim_uints!( + #[usize =, $($rest)*] + $m!() + ); + }; + ( + #[size = size, $(rest:tt)*] + $m:ident!() + ) => { + impl_for_all_prim_uints!( + #[usize = usize, $($rest)*] + $m!() + ); + }; + ( + #[usize = $($usize:ident)?, NonZero = $NonZero:ident] + $m:ident!() + ) => { + impl_for_all_prim_uints!( + #[usize = $($usize)?, NonZero = $NonZero, NonZero = $((NonZero<$usize>))?] + $m!() + ); + }; + ( + #[usize = $($usize:ident)?, NonZero =] + $m:ident!() + ) => { + impl_for_all_prim_uints!( + #[usize = $($usize)?, NonZero =, NonZero =] + $m!() + ); + }; + ( + #[usize = $($usize:ident)?, NonZero = $($NonZero:ident)?, NonZero = $(($($NonZeroUsize:tt)*))?] + $m:ident!() + ) => { + $m!(u8, UInt<8>); + $m!(u16, UInt<16>); + $m!(u32, UInt<32>); + $m!(u64, UInt<64>); + $m!(u128, UInt<128>); + $($m!($NonZero, UInt<8>);)? + $($m!($NonZero, UInt<16>);)? + $($m!($NonZero, UInt<32>);)? + $($m!($NonZero, UInt<64>);)? + $($m!($NonZero, UInt<128>);)? + $($m!( + /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] + $usize, UInt<64> + );)? + $($m!( + /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] + $($NonZeroUsize)*, UInt<64> + );)? + }; +} -impl_prim_int!( - /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] - usize, UInt<64> +macro_rules! impl_for_all_prim_sints { + ( + #[size =, $(rest:tt)*] + $m:ident!() + ) => { + impl_for_all_prim_sints!( + #[isize =, $($rest)*] + $m!() + ); + }; + ( + #[size = size, $(rest:tt)*] + $m:ident!() + ) => { + impl_for_all_prim_sints!( + #[isize = isize, $($rest)*] + $m!() + ); + }; + ( + #[isize = $($isize:ident)?, NonZero = $NonZero:ident] + $m:ident!() + ) => { + impl_for_all_prim_sints!( + #[isize = $($isize)?, NonZero = $NonZero, NonZero = $((NonZero<$isize>))?] + $m!() + ); + }; + ( + #[isize = $($isize:ident)?, NonZero =] + $m:ident!() + ) => { + impl_for_all_prim_sints!( + #[isize = $($isize)?, NonZero =, NonZero =] + $m!() + ); + }; + ( + #[isize = $($isize:ident)?, NonZero = $($NonZero:ident)?, NonZero = $(($($NonZeroIsize:tt)*))?] + $m:ident!() + ) => { + $m!(i8, SInt<8>); + $m!(i16, SInt<16>); + $m!(i32, SInt<32>); + $m!(i64, SInt<64>); + $m!(i128, SInt<128>); + $($m!($NonZero, SInt<8>);)? + $($m!($NonZero, SInt<16>);)? + $($m!($NonZero, SInt<32>);)? + $($m!($NonZero, SInt<64>);)? + $($m!($NonZero, SInt<128>);)? + $($m!( + /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] + $isize, SInt<64> + );)? + $($m!( + /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] + $($NonZeroIsize)*, SInt<64> + );)? + }; +} + +impl_for_all_prim_uints!( + #[usize = usize, NonZero =] + impl_prim_int_to_expr!() ); -impl_prim_int!( - /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] - isize, SInt<64> +impl_for_all_prim_sints!( + #[isize = isize, NonZero =] + impl_prim_int_to_expr!() +); + +macro_rules! impl_prim_int_from_value { + ($prim_int:ident, UInt<$width:literal>) => { + impl_prim_int_from_value!($prim_int, UInt<$width>, UIntValue>); + }; + ($prim_int:ident, SInt<$width:literal>) => { + impl_prim_int_from_value!($prim_int, SInt<$width>, SIntValue>); + }; + ($prim_int:ident, $ty:ty, $value:ty) => { + impl From<$value> for $prim_int { + fn from(value: $value) -> Self { + value.as_int() + } + } + + impl<'a> From<&'a mut $value> for $prim_int { + fn from(value: &'a mut $value) -> Self { + value.as_int() + } + } + + impl From> for $prim_int { + fn from(value: SimValue<$ty>) -> Self { + value.as_int() + } + } + + impl<'a> From<&'a mut SimValue<$ty>> for $prim_int { + fn from(value: &'a mut SimValue<$ty>) -> Self { + value.as_int() + } + } + + impl<'a> From<&'a SimValue<$ty>> for $prim_int { + fn from(value: &'a SimValue<$ty>) -> Self { + value.as_int() + } + } + + impl<'a> From<&'a $value> for $prim_int { + fn from(value: &'a $value) -> Self { + value.as_int() + } + } + + impl $value { + pub fn as_int(&self) -> $prim_int { + let mut le_bytes = (0 as $prim_int).to_le_bytes(); + let bitslice = BitSlice::::from_slice_mut(&mut le_bytes); + bitslice.clone_from_bitslice(self.bits()); + $prim_int::from_le_bytes(le_bytes) + } + } + }; +} + +impl_for_all_prim_uints!( + #[usize =, NonZero =] + impl_prim_int_from_value!() +); + +impl_for_all_prim_sints!( + #[isize =, NonZero =] + impl_prim_int_from_value!() ); pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { @@ -1307,6 +1828,23 @@ impl ToLiteralBits for bool { } } +impl ToSimValueInner for bool { + fn to_sim_value_inner(this: &Self) -> ::SimValue { + *this + } + fn into_sim_value_inner(this: Self) -> ::SimValue { + this + } +} + +impl std::ops::Not for Valueless { + type Output = Valueless; + + fn not(self) -> Self::Output { + self + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/fayalite/src/memory.rs b/crates/fayalite/src/memory.rs index 46eb59bd..83e74376 100644 --- a/crates/fayalite/src/memory.rs +++ b/crates/fayalite/src/memory.rs @@ -7,7 +7,10 @@ use crate::{ array::{Array, ArrayType}, bundle::{Bundle, BundleType}, clock::Clock, - expr::{Expr, Flow, ToExpr, ToLiteralBits, ops::BundleLiteral, repeat}, + expr::{ + Expr, Flow, ToExpr, ToLiteralBits, ValueType, ops::BundleLiteral, repeat, + value_category::ValueCategoryExpr, + }, hdl, int::{Bool, DynSize, Size, UInt, UIntType}, intern::{Intern, Interned}, @@ -366,10 +369,16 @@ impl fmt::Debug for MemPort { } } -impl MemPort { - pub fn ty(&self) -> T::Port { +impl ValueType for MemPort { + type Type = T::Port; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> T::Port { T::port_ty(self) } +} + +impl MemPort { pub fn source_location(&self) -> SourceLocation { self.source_location } @@ -830,7 +839,7 @@ impl MemBuilder { depth: Option, initial_value: Expr, ) -> Interned { - let initial_value_ty = Expr::ty(initial_value); + let initial_value_ty = initial_value.ty(); assert_eq!( *mem_element_type, Element::from_canonical(initial_value_ty.element()), @@ -1011,7 +1020,7 @@ impl MemBuilder { target.depth, initial_value, )); - target.depth = Some(Expr::ty(initial_value).len()); + target.depth = Some(initial_value.ty().len()); } #[track_caller] pub fn initial_value_bit_slice(&mut self, initial_value: Interned) { diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 5ffeaae2..9d1a0e76 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -8,12 +8,13 @@ use crate::{ clock::{Clock, ClockDomain}, enum_::{Enum, EnumMatchVariantsIter, EnumType}, expr::{ - Expr, Flow, ToExpr, + Expr, Flow, ToExpr, ValueType, ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, }, + value_category::ValueCategoryExpr, }, formal::FormalKind, int::{Bool, DynSize, Size}, @@ -205,7 +206,7 @@ impl StmtConnect { source_location, } = *self; assert!( - Expr::ty(lhs).can_connect(Expr::ty(rhs)), + lhs.ty().can_connect(rhs.ty()), "can't connect types that are not equivalent:\nlhs type:\n{lhs_orig_ty:?}\nrhs type:\n{rhs_orig_ty:?}\nat: {source_location}", ); assert!( @@ -219,14 +220,14 @@ impl StmtConnect { match Expr::flow(rhs) { Flow::Source | Flow::Duplex => {} Flow::Sink => assert!( - Expr::ty(rhs).is_passive(), + rhs.ty().is_passive(), "can't connect from sink with non-passive type\nat: {source_location}" ), } } #[track_caller] fn assert_validity(&self) { - self.assert_validity_with_original_types(Expr::ty(self.lhs), Expr::ty(self.rhs)); + self.assert_validity_with_original_types(self.lhs.ty(), self.rhs.ty()); } } @@ -331,7 +332,7 @@ impl Copy for StmtMatch {} impl StmtMatch { #[track_caller] fn assert_validity(&self) { - assert_eq!(Expr::ty(self.expr).variants().len(), self.blocks.len()); + assert_eq!(self.expr.ty().variants().len(), self.blocks.len()); } } @@ -765,6 +766,15 @@ impl fmt::Debug for Instance { } } +impl ValueType for Instance { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> T { + self.instantiated.io_ty() + } +} + impl Instance { pub fn canonical(self) -> Instance { let Self { @@ -828,9 +838,6 @@ impl Instance { pub fn must_connect_to(&self) -> bool { true } - pub fn ty(&self) -> T { - self.instantiated.io_ty() - } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -2028,7 +2035,7 @@ impl RegBuilder { init: _, ty: _, } = self; - let ty = Expr::ty(init); + let ty = init.ty(); RegBuilder { name, source_location, @@ -2597,7 +2604,7 @@ pub fn enum_match_variants_helper( ModuleBuilder::with(|m| { let mut impl_ = m.impl_.borrow_mut(); let body = impl_.body.builder_normal_body(); - let enum_ty = Expr::ty(base); + let enum_ty = base.ty(); let outer_block: BlockId = m.block_stack.top(); let blocks = Interned::from_iter(enum_ty.variants().iter().map(|_| body.new_block())); body.block(outer_block).stmts.push( @@ -2649,7 +2656,7 @@ pub fn connect_any_with_loc( rhs, source_location, }; - connect.assert_validity_with_original_types(Expr::ty(lhs_orig), Expr::ty(rhs_orig)); + connect.assert_validity_with_original_types(lhs_orig.ty(), rhs_orig.ty()); ModuleBuilder::with(|m| { m.impl_ .borrow_mut() @@ -2764,7 +2771,7 @@ pub fn memory_with_init_and_loc( source_location: SourceLocation, ) -> MemBuilder { let initial_value = initial_value.to_expr(); - let mut retval = memory_array_with_loc(name, Expr::ty(initial_value), source_location); + let mut retval = memory_array_with_loc(name, initial_value.ty(), source_location); retval.initial_value(initial_value); retval } @@ -2807,6 +2814,15 @@ pub struct ModuleIO { source_location: SourceLocation, } +impl ValueType for ModuleIO { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + impl fmt::Debug for ModuleIO { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ModuleIO") @@ -2908,9 +2924,6 @@ impl ModuleIO { unreachable!() } } - pub fn ty(&self) -> T { - self.ty - } } #[derive(PartialEq, Eq, Hash, Clone, Copy)] diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index bd4e939c..73f92dd2 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -521,7 +521,7 @@ impl State { Entry::Vacant(entry) => ( *entry.insert(Resets::with_new_nodes( &mut self.reset_graph, - Expr::ty(expr), + expr.ty(), source_location, )), true, @@ -1020,7 +1020,7 @@ fn cast_bit_op( } macro_rules! match_arg_ty { ($($Variant:ident),*) => { - *match Expr::ty(arg) { + *match arg.ty() { CanonicalType::Array(_) | CanonicalType::Enum(_) | CanonicalType::Bundle(_) @@ -1660,7 +1660,8 @@ impl RunPassDispatch for AnyReg { let clock_domain = Expr::::from_canonical( Expr::canonical(reg.clock_domain()).run_pass(pass_args)?.0, ); - match Expr::ty(clock_domain) + match clock_domain + .ty() .field_by_name("rst".intern()) .expect("ClockDomain has rst field") .ty diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index bd5f7d52..3e013e70 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -528,7 +528,7 @@ fn connect_port( rhs: Expr, source_location: SourceLocation, ) { - if Expr::ty(lhs) == Expr::ty(rhs) { + if lhs.ty() == rhs.ty() { stmts.push( StmtConnect { lhs, @@ -539,7 +539,7 @@ fn connect_port( ); return; } - match (Expr::ty(lhs), Expr::ty(rhs)) { + match (lhs.ty(), rhs.ty()) { (CanonicalType::Bundle(lhs_type), CanonicalType::UInt(_) | CanonicalType::Bool(_)) => { let lhs = Expr::::from_canonical(lhs); for field in lhs_type.fields() { @@ -586,8 +586,8 @@ fn connect_port( | (CanonicalType::PhantomConst(_), _) | (CanonicalType::DynSimOnly(_), _) => unreachable!( "trying to connect memory ports:\n{:?}\n{:?}", - Expr::ty(lhs), - Expr::ty(rhs), + lhs.ty(), + rhs.ty(), ), } } @@ -607,14 +607,17 @@ fn match_int_tag( }; }; let mut retval = StmtIf { - cond: int_tag_expr - .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(next_to_last_variant_index)), + cond: int_tag_expr.cmp_eq( + int_tag_expr + .ty() + .from_int_wrapping(next_to_last_variant_index), + ), source_location, blocks: [next_to_last_block, last_block], }; for (variant_index, block) in blocks_iter.rev() { retval = StmtIf { - cond: int_tag_expr.cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(variant_index)), + cond: int_tag_expr.cmp_eq(int_tag_expr.ty().from_int_wrapping(variant_index)), source_location, blocks: [ block, @@ -657,7 +660,7 @@ impl Folder for State { ExprEnum::VariantAccess(op) => { let folded_base_expr = Expr::canonical(op.base()).fold(self)?; Ok(*Expr::expr_enum(self.handle_variant_access( - Expr::ty(op.base()), + op.base().ty(), folded_base_expr, op.variant_index(), )?)) @@ -867,7 +870,7 @@ impl Folder for State { }) => { let folded_expr = Expr::canonical(expr).fold(self)?; let folded_blocks = blocks.fold(self)?; - self.handle_match(Expr::ty(expr), folded_expr, source_location, &folded_blocks) + self.handle_match(expr.ty(), folded_expr, source_location, &folded_blocks) } Stmt::Connect(StmtConnect { lhs, @@ -878,8 +881,8 @@ impl Folder for State { let folded_rhs = rhs.fold(self)?; let mut output_stmts = vec![]; self.handle_stmt_connect( - Expr::ty(lhs), - Expr::ty(rhs), + lhs.ty(), + rhs.ty(), folded_lhs, folded_rhs, source_location, diff --git a/crates/fayalite/src/module/transform/simplify_memories.rs b/crates/fayalite/src/module/transform/simplify_memories.rs index 35f186d3..662921b0 100644 --- a/crates/fayalite/src/module/transform/simplify_memories.rs +++ b/crates/fayalite/src/module/transform/simplify_memories.rs @@ -530,7 +530,7 @@ impl ModuleState { connect_read( output_stmts, wire_read, - Expr::::from_canonical(port_read).cast_bits_to(Expr::ty(wire_read)), + Expr::::from_canonical(port_read).cast_bits_to(wire_read.ty()), ); }; let connect_write_enum = diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs index eb6a7584..70920f74 100644 --- a/crates/fayalite/src/phantom_const.rs +++ b/crates/fayalite/src/phantom_const.rs @@ -3,7 +3,7 @@ use crate::{ expr::{ - Expr, ToExpr, + Expr, ToExpr, ValueType, ops::{ExprPartialEq, ExprPartialOrd}, }, int::Bool, @@ -374,48 +374,46 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst { impl ExprPartialEq for PhantomConst { fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); true.to_expr() } fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); false.to_expr() } } impl ExprPartialOrd for PhantomConst { fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); false.to_expr() } fn cmp_le(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); true.to_expr() } fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); false.to_expr() } fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); + assert_eq!(lhs.ty(), rhs.ty()); true.to_expr() } } impl SimValuePartialEq for PhantomConst { fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - assert_eq!(SimValue::ty(this), SimValue::ty(other)); + assert_eq!(this.ty(), other.ty()); true } } impl ToSimValue for PhantomConst { - type Type = PhantomConst; - fn to_sim_value(&self) -> SimValue { SimValue::from_value(*self, *self) } @@ -479,7 +477,7 @@ impl_phantom_const_get! { impl_phantom_const_get! { impl PhantomConstGet for Expr> { fn get(&self) -> _ { - PhantomConst::get(Expr::ty(*self)) + PhantomConst::get(self.ty()) } } } diff --git a/crates/fayalite/src/platform.rs b/crates/fayalite/src/platform.rs index 194aa6e3..bf074345 100644 --- a/crates/fayalite/src/platform.rs +++ b/crates/fayalite/src/platform.rs @@ -3,7 +3,7 @@ use crate::{ bundle::{Bundle, BundleField, BundleType}, - expr::{Expr, ExprEnum}, + expr::{Expr, ExprEnum, ValueType}, intern::{Intern, Interned}, module::{Module, ModuleBuilder, ModuleIO, connect_with_loc, instance_with_loc, wire_with_loc}, source_location::SourceLocation, @@ -616,7 +616,7 @@ impl Peripheral { drop(state); let Self { ty, common } = self; let instance_io_field = Expr::field(output, &common.id.name); - assert_eq!(ty, Expr::ty(instance_io_field)); + assert_eq!(ty, instance_io_field.ty()); Ok(UsedPeripheral { instance_io_field, common, @@ -654,7 +654,7 @@ impl UsedPeripheral { ref common, } = *self; PeripheralRef { - ty: Expr::ty(instance_io_field), + ty: instance_io_field.ty(), common, } } @@ -915,7 +915,7 @@ impl<'a, T: Type> PeripheralRef<'a, T> { main_module_io_fields.push(BundleField { name: self.name(), flipped: self.is_input(), - ty: Expr::ty(canonical_wire), + ty: canonical_wire.ty(), }); on_use_function(&mut **shared_state, self.canonical(), canonical_wire); drop(on_use_state); diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 4cc173e8..4c5bfdf4 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, repeat, + ReduceBits, ToExpr, ValueType, repeat, }, formal::{ MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, diff --git a/crates/fayalite/src/reg.rs b/crates/fayalite/src/reg.rs index 20e0b944..7f506552 100644 --- a/crates/fayalite/src/reg.rs +++ b/crates/fayalite/src/reg.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ clock::ClockDomain, - expr::{Expr, Flow}, + expr::{Expr, Flow, ValueType, value_category::ValueCategoryExpr}, intern::Interned, module::{NameId, ScopedNameId}, reset::{Reset, ResetType}, @@ -20,7 +20,16 @@ pub struct Reg { init: Option>, } -impl fmt::Debug for Reg { +impl ValueType for Reg { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl fmt::Debug for Reg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { name, @@ -68,7 +77,7 @@ impl Reg { "register type must be a storable type" ); if let Some(init) = init { - assert_eq!(ty, Expr::ty(init), "register's type must match init type"); + assert_eq!(ty, init.ty(), "register's type must match init type"); } Self { name: scoped_name, @@ -78,9 +87,6 @@ impl Reg { init, } } - pub fn ty(&self) -> T { - self.ty - } pub fn source_location(&self) -> SourceLocation { self.source_location } diff --git a/crates/fayalite/src/reset.rs b/crates/fayalite/src/reset.rs index 5dff2784..d9b7e8ac 100644 --- a/crates/fayalite/src/reset.rs +++ b/crates/fayalite/src/reset.rs @@ -2,8 +2,9 @@ // See Notices.txt for copyright information use crate::{ clock::Clock, - expr::{Expr, ToExpr, ops}, + expr::{Expr, ValueType, ops}, int::{Bool, SInt, UInt}, + prelude::SimValue, source_location::SourceLocation, ty::{ CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, @@ -132,29 +133,34 @@ macro_rules! reset_type { } pub trait $Trait { - fn $trait_fn(&self) -> Expr<$name>; + type Output: ValueType; + fn $trait_fn(&self) -> Self::Output; } impl $Trait for &'_ T { - fn $trait_fn(&self) -> Expr<$name> { + type Output = T::Output; + fn $trait_fn(&self) -> Self::Output { (**self).$trait_fn() } } impl $Trait for &'_ mut T { - fn $trait_fn(&self) -> Expr<$name> { + type Output = T::Output; + fn $trait_fn(&self) -> Self::Output { (**self).$trait_fn() } } impl $Trait for Box { - fn $trait_fn(&self) -> Expr<$name> { + type Output = T::Output; + fn $trait_fn(&self) -> Self::Output { (**self).$trait_fn() } } $($impl_trait $Trait for Expr<$name> { - fn $trait_fn(&self) -> Expr<$name> { + type Output = Expr<$name>; + fn $trait_fn(&self) -> Self::Output { *self } })? @@ -171,13 +177,15 @@ reset_type!( ); impl ToSyncReset for bool { - fn to_sync_reset(&self) -> Expr { - self.to_expr().to_sync_reset() + type Output = SimValue; + fn to_sync_reset(&self) -> Self::Output { + SimValue::from_value(SyncReset, *self) } } impl ToAsyncReset for bool { - fn to_async_reset(&self) -> Expr { - self.to_expr().to_async_reset() + type Output = SimValue; + fn to_async_reset(&self) -> Self::Output { + SimValue::from_value(SyncReset, *self) } } diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 808ead40..bf24befb 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -1504,9 +1504,10 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo fn call(self, state: &mut interpreter::State) -> Self::Output { let Self { compiled_value, io } = self; match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => Expr::ty(io) + Some(TypeLenSingle::SmallSlot) => io + .ty() .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), - Some(TypeLenSingle::BigSlot) => Expr::ty(io).value_from_int_wrapping( + Some(TypeLenSingle::BigSlot) => io.ty().value_from_int_wrapping( state.big_slots[compiled_value.range.big_slots.start].clone(), ), Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), @@ -2889,7 +2890,7 @@ impl SimulationImpl { }, ); } - let size = Expr::ty(io).size(); + let size = io.ty().size(); let mut opaque = OpaqueSimValue::with_capacity(size); opaque.rewrite_with(size, |mut writer| { SimulationImpl::read_write_sim_value_helper( @@ -2922,7 +2923,7 @@ impl SimulationImpl { ); writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) }); - SimValue::from_opaque(Expr::ty(io), opaque) + SimValue::from_opaque(io.ty(), opaque) } /// doesn't modify `opaque` fn value_changed( @@ -3006,7 +3007,7 @@ impl SimulationImpl { .get_module_mut(which_module) .write_helper(io, which_module); self.event_queue.add_event_for_now(EventKind::State); - assert_eq!(Expr::ty(io), SimValue::ty(value)); + assert_eq!(io.ty(), value.ty()); Self::read_write_sim_value_helper( &mut self.state, compiled_value, @@ -3272,7 +3273,7 @@ macro_rules! impl_simulation_methods { value: impl ToExpr, ) { let value = value.to_expr(); - assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); + assert_eq!(io.ty(), value.ty(), "type mismatch"); let value = value .to_literal_bits() .expect("the value that is being written to an input must be a literal"); @@ -3343,7 +3344,7 @@ macro_rules! impl_simulation_methods { pub $($async)? fn write>(&mut $self, io: Expr, value: V) { $self.sim_impl.borrow_mut().write( Expr::canonical(io), - &SimValue::into_canonical(value.into_sim_value_with_type(Expr::ty(io))), + &SimValue::into_canonical(value.into_sim_value_with_type(io.ty())), $which_module, ); } diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index 7a0ac0a2..40108904 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -1714,7 +1714,7 @@ impl MakeTraceDeclTarget { } fn ty(self) -> CanonicalType { match self { - MakeTraceDeclTarget::Expr(expr) => Expr::ty(expr), + MakeTraceDeclTarget::Expr(expr) => expr.ty(), MakeTraceDeclTarget::Memory { ty, .. } => ty, } } @@ -2771,7 +2771,7 @@ impl Compiler { let retval = parts .into_iter() .map(|part| part.cast_to_bits()) - .reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width)) + .reduce(|accumulator, part| accumulator | (part << accumulator.ty().width)) .unwrap_or_else(|| UInt[0].zero().to_expr()); let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); let retval = self @@ -2783,7 +2783,7 @@ impl Compiler { instantiated_module: InstantiatedModule, expr: ops::CastToBits, ) -> CompiledValue { - match Expr::ty(expr.arg()) { + match expr.arg().ty() { CanonicalType::UInt(_) => { self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) } @@ -2949,7 +2949,7 @@ impl Compiler { return retval; } let mut cast_bit = |arg: Expr| { - let src_signed = match Expr::ty(arg) { + let src_signed = match arg.ty() { CanonicalType::UInt(_) => false, CanonicalType::SInt(_) => true, CanonicalType::Bool(_) => false, @@ -2963,7 +2963,7 @@ impl Compiler { CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => unreachable!(), }; - let dest_signed = match Expr::ty(expr) { + let dest_signed = match expr.ty() { CanonicalType::UInt(_) => false, CanonicalType::SInt(_) => true, CanonicalType::Bool(_) => false, @@ -2977,22 +2977,23 @@ impl Compiler { CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => unreachable!(), }; - self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| { - match (src_signed, dest_signed) { - (false, false) | (true, true) => { - vec![Insn::Copy { dest, src }] - } - (false, true) => vec![Insn::CastToSInt { - dest, - src, - dest_width: 1, - }], - (true, false) => vec![Insn::CastToUInt { - dest, - src, - dest_width: 1, - }], + self.simple_nary_big_expr(instantiated_module, expr.ty(), [arg], |dest, [src]| match ( + src_signed, + dest_signed, + ) { + (false, false) | (true, true) => { + vec![Insn::Copy { dest, src }] } + (false, true) => vec![Insn::CastToSInt { + dest, + src, + dest_width: 1, + }], + (true, false) => vec![Insn::CastToUInt { + dest, + src, + dest_width: 1, + }], }) .into() }; @@ -3032,21 +3033,13 @@ impl Compiler { }) .into(), ExprEnum::PhantomConst(_) => self - .compile_aggregate_literal(instantiated_module, Expr::ty(expr), Interned::default()) + .compile_aggregate_literal(instantiated_module, expr.ty(), Interned::default()) .into(), ExprEnum::BundleLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.field_values(), - ) + .compile_aggregate_literal(instantiated_module, expr.ty(), literal.field_values()) .into(), ExprEnum::ArrayLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.element_values(), - ) + .compile_aggregate_literal(instantiated_module, expr.ty(), literal.element_values()) .into(), ExprEnum::EnumLiteral(expr) => { let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; @@ -3074,13 +3067,13 @@ impl Compiler { ExprEnum::NotU(expr) => self .simple_nary_big_expr( instantiated_module, - Expr::ty(expr.arg()).canonical(), + expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { vec![Insn::NotU { dest, src, - width: Expr::ty(expr.arg()).width(), + width: expr.arg().ty().width(), }] }, ) @@ -3088,7 +3081,7 @@ impl Compiler { ExprEnum::NotS(expr) => self .simple_nary_big_expr( instantiated_module, - Expr::ty(expr.arg()).canonical(), + expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| vec![Insn::NotS { dest, src }], ) @@ -3096,7 +3089,7 @@ impl Compiler { ExprEnum::NotB(expr) => self .simple_nary_big_expr( instantiated_module, - Expr::ty(expr.arg()).canonical(), + expr.arg().ty().canonical(), [Expr::canonical(expr.arg())], |dest, [src]| { vec![Insn::NotU { @@ -3600,12 +3593,12 @@ impl Compiler { .map_ty(Bundle::from_canonical) .field_by_index(expr.field_index()), ExprEnum::VariantAccess(variant_access) => { - let start = Expr::ty(variant_access.base()).discriminant_bit_width(); - let len = Expr::ty(expr).bit_width(); + let start = variant_access.base().ty().discriminant_bit_width(); + let len = expr.ty().bit_width(); self.compile_expr( instantiated_module, variant_access.base().cast_to_bits()[start..start + len] - .cast_bits_to(Expr::ty(expr)), + .cast_bits_to(expr.ty()), ) } ExprEnum::ArrayIndex(expr) => self @@ -3627,45 +3620,39 @@ impl Compiler { .map_ty(Array::from_canonical) .element_dyn(index_slot) } - ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 { + ExprEnum::ReduceBitAndU(expr) => if expr.arg().ty().width() == 0 { self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) } else { self.compile_expr( instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), + Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))), ) } .into(), - ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 { + ExprEnum::ReduceBitAndS(expr) => if expr.arg().ty().width() == 0 { self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) } else { self.compile_expr( instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), + Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))), ) } .into(), - ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 { + ExprEnum::ReduceBitOrU(expr) => if expr.arg().ty().width() == 0 { self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) } else { self.compile_expr( instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))), ) } .into(), - ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 { + ExprEnum::ReduceBitOrS(expr) => if expr.arg().ty().width() == 0 { self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) } else { self.compile_expr( instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))), ) } .into(), @@ -3678,7 +3665,7 @@ impl Compiler { vec![Insn::ReduceBitXor { dest, src, - input_width: Expr::ty(expr.arg()).width(), + input_width: expr.arg().ty().width(), }] }, ) @@ -3692,7 +3679,7 @@ impl Compiler { vec![Insn::ReduceBitXor { dest, src, - input_width: Expr::ty(expr.arg()).width(), + input_width: expr.arg().ty().width(), }] }, ) @@ -3790,8 +3777,8 @@ impl Compiler { mut rhs: Expr, source_location: SourceLocation, ) { - if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() { - match Expr::ty(lhs) { + if lhs.ty() != rhs.ty() || !lhs.ty().is_passive() { + match lhs.ty() { CanonicalType::UInt(lhs_ty) => { rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); } @@ -3800,7 +3787,7 @@ impl Compiler { } CanonicalType::Bool(_) => unreachable!(), CanonicalType::Array(lhs_ty) => { - let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else { + let CanonicalType::Array(rhs_ty) = rhs.ty() else { unreachable!(); }; assert_eq!(lhs_ty.len(), rhs_ty.len()); @@ -3820,13 +3807,13 @@ impl Compiler { return; } CanonicalType::Enum(lhs_ty) => { - let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else { + let CanonicalType::Enum(rhs_ty) = rhs.ty() else { unreachable!(); }; todo!("handle connect with different enum types"); } CanonicalType::Bundle(lhs_ty) => { - let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else { + let CanonicalType::Bundle(rhs_ty) = rhs.ty() else { unreachable!(); }; assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len()); diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index ff836d52..112ef1ca 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -6,7 +6,10 @@ use crate::{ bundle::{Bundle, BundleType}, clock::Clock, enum_::{Enum, EnumType}, - expr::{CastBitsTo, Expr, ToExpr}, + expr::{ + CastBitsTo, Expr, ToExpr, ToValueless, ValueType, Valueless, + value_category::{ValueCategorySimValue, ValueCategoryValue}, + }, int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, reset::{AsyncReset, Reset, SyncReset}, source_location::SourceLocation, @@ -26,6 +29,7 @@ use std::{ borrow::{Borrow, BorrowMut, Cow}, fmt::{self, Write}, hash::{BuildHasher, Hash, Hasher, RandomState}, + num::NonZero, ops::{Deref, DerefMut, Index, IndexMut}, sync::{Arc, Mutex}, }; @@ -136,7 +140,7 @@ impl + Serialize> Serialize for SimValue { S: Serializer, { SerdeSimValue { - ty: SimValue::ty(self), + ty: self.ty(), value: std::borrow::Cow::Borrowed(&*self), } .serialize(serializer) @@ -157,6 +161,15 @@ pub struct SimValue { inner: AlternatingCell>, } +impl ValueType for SimValue { + type Type = T; + type ValueCategory = ValueCategorySimValue; + + fn ty(&self) -> Self::Type { + self.inner.share().ty + } +} + impl> fmt::Display for SimValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { T::SimValue::fmt(self, f) @@ -218,9 +231,6 @@ impl SimValue { inner: AlternatingCell::new_unique(inner), } } - pub fn ty(this: &Self) -> T { - this.inner.share().ty - } pub fn into_opaque(this: Self) -> OpaqueSimValue { this.inner.into_inner().into_opaque() } @@ -259,7 +269,7 @@ impl SimValue { SimValue::from_opaque(ty.canonical(), opaque) } pub fn canonical(this: &Self) -> SimValue { - SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone()) + SimValue::from_opaque(this.ty().canonical(), Self::opaque(this).clone()) } #[track_caller] pub fn from_dyn_int(v: SimValue) -> Self @@ -280,7 +290,7 @@ impl SimValue { where T: IntType, { - SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone()) + SimValue::from_opaque(this.ty().as_dyn_int(), Self::opaque(&this).clone()) } #[track_caller] pub fn from_bundle(v: SimValue) -> Self @@ -302,7 +312,7 @@ impl SimValue { T: BundleType, { SimValue::from_opaque( - Bundle::from_canonical(Self::ty(this).canonical()), + Bundle::from_canonical(this.ty().canonical()), Self::opaque(&this).clone(), ) } @@ -326,7 +336,7 @@ impl SimValue { T: EnumType, { SimValue::from_opaque( - Enum::from_canonical(Self::ty(this).canonical()), + Enum::from_canonical(this.ty().canonical()), Self::opaque(&this).clone(), ) } @@ -357,8 +367,6 @@ impl fmt::Debug for SimValue { } impl ToExpr for SimValue { - type Type = T; - #[track_caller] fn to_expr(&self) -> Expr { let inner = self.inner.share(); @@ -450,48 +458,160 @@ impl, U: Type> PartialEq> for SimValue { } } -impl SimValuePartialEq for UIntType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +pub trait SimValueEq: SimValuePartialEq {} + +impl Eq for SimValue {} + +pub trait SimValuePartialOrd: SimValuePartialEq { + #[track_caller] + fn sim_value_partial_cmp( + this: &SimValue, + other: &SimValue, + ) -> Option; +} + +impl, U: Type> PartialOrd> for SimValue { + #[track_caller] + fn partial_cmp(&self, other: &SimValue) -> Option { + T::sim_value_partial_cmp(self, other) } } -impl SimValuePartialEq for SIntType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +pub trait SimValueOrd: SimValuePartialOrd + SimValueEq { + #[track_caller] + fn sim_value_cmp(this: &SimValue, other: &SimValue) -> std::cmp::Ordering; +} + +impl Ord for SimValue { + #[track_caller] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + T::sim_value_cmp(self, other) } } -impl SimValuePartialEq for Bool { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +impl SimValuePartialEq> for UIntType { + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + this.hdl_eq(&other) } } -impl SimValuePartialEq for Clock { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +impl SimValueEq for UIntType {} + +impl SimValuePartialOrd> for UIntType { + fn sim_value_partial_cmp( + this: &SimValue, + other: &SimValue>, + ) -> Option { + Some(this.hdl_cmp(other)) } } -impl SimValuePartialEq for Reset { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +impl SimValueOrd for UIntType { + fn sim_value_cmp(this: &SimValue, other: &SimValue) -> std::cmp::Ordering { + this.hdl_cmp(other) } } -impl SimValuePartialEq for SyncReset { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +impl SimValuePartialEq> for SIntType { + fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { + this.hdl_eq(other) } } -impl SimValuePartialEq for AsyncReset { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other +impl SimValueEq for SIntType {} + +impl SimValuePartialOrd> for SIntType { + fn sim_value_partial_cmp( + this: &SimValue, + other: &SimValue>, + ) -> Option { + Some(this.hdl_cmp(other)) } } +impl SimValueOrd for SIntType { + fn sim_value_cmp(this: &SimValue, other: &SimValue) -> std::cmp::Ordering { + this.hdl_cmp(other) + } +} + +macro_rules! impl_sim_value_cmp_as_bool { + ($ty:ident) => { + impl SimValuePartialEq for $ty { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + **this == **other + } + } + + impl SimValueEq for $ty {} + + impl SimValuePartialOrd for $ty { + fn sim_value_partial_cmp( + this: &SimValue, + other: &SimValue, + ) -> Option { + bool::partial_cmp(this, other) + } + } + + impl SimValueOrd for $ty { + fn sim_value_cmp(this: &SimValue, other: &SimValue) -> std::cmp::Ordering { + bool::cmp(this, other) + } + } + }; +} + +impl_sim_value_cmp_as_bool!(Bool); +impl_sim_value_cmp_as_bool!(Clock); +impl_sim_value_cmp_as_bool!(Reset); +impl_sim_value_cmp_as_bool!(SyncReset); +impl_sim_value_cmp_as_bool!(AsyncReset); + +macro_rules! forward_unary_op_to_value { + (#[trait = $($Trait:tt)+] fn $f:ident();) => { + impl<'a, T: Type, O: Type> $($Trait)+ for &'a SimValue + where + &'a T::SimValue: $($Trait)+>, + Valueless: $($Trait)+>, + { + type Output = SimValue; + + fn $f(self) -> Self::Output { + let ty = self.to_valueless().$f().ty(); + (&**self) + .$f() + .into_sim_value_with_type(self.to_valueless().$f().ty()) + } + } + + impl $($Trait)+ for SimValue + where + T::SimValue: $($Trait)+>, + Valueless: $($Trait)+>, + { + type Output = SimValue; + + fn $f(self) -> Self::Output { + let ty = self.to_valueless().$f().ty(); + SimValue::into_value(self) + .$f() + .into_sim_value_with_type(ty) + } + } + }; +} + +forward_unary_op_to_value! { + #[trait = std::ops::Neg] + fn neg(); +} + +forward_unary_op_to_value! { + #[trait = std::ops::Not] + fn not(); +} + #[doc(hidden)] pub mod match_sim_value { use crate::{ @@ -603,9 +723,7 @@ pub mod match_sim_value { } } -pub trait ToSimValue: ToSimValueWithType<::Type> { - type Type: Type; - +pub trait ToSimValue: ToSimValueWithType<::Type> + ValueType { #[track_caller] fn to_sim_value(&self) -> SimValue; #[track_caller] @@ -647,31 +765,31 @@ pub trait ToSimValueWithType { macro_rules! forward_to_sim_value_with_type { ([$($generics:tt)*] $ty:ty) => { - impl<$($generics)*> ToSimValueWithType<::Type> for $ty { - fn to_sim_value_with_type(&self, ty: ::Type) -> SimValue<::Type> { + impl<$($generics)*> ToSimValueWithType<::Type> for $ty { + fn to_sim_value_with_type(&self, ty: ::Type) -> SimValue<::Type> { let retval = Self::to_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); + assert_eq!(retval.ty(), ty); retval } #[track_caller] - fn into_sim_value_with_type(self, ty: ::Type) -> SimValue<::Type> + fn into_sim_value_with_type(self, ty: ::Type) -> SimValue<::Type> where Self: Sized, { let retval = Self::into_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); + assert_eq!(retval.ty(), ty); retval } #[track_caller] - fn arc_into_sim_value_with_type(self: Arc, ty: ::Type) -> SimValue<::Type> { + fn arc_into_sim_value_with_type(self: Arc, ty: ::Type) -> SimValue<::Type> { let retval = Self::arc_into_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); + assert_eq!(retval.ty(), ty); retval } #[track_caller] - fn arc_to_sim_value_with_type(self: &Arc, ty: ::Type) -> SimValue<::Type> { + fn arc_to_sim_value_with_type(self: &Arc, ty: ::Type) -> SimValue<::Type> { let retval = Self::arc_to_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); + assert_eq!(retval.ty(), ty); retval } } @@ -679,7 +797,6 @@ macro_rules! forward_to_sim_value_with_type { } impl ToSimValue for SimValue { - type Type = T; fn to_sim_value(&self) -> SimValue { self.clone() } @@ -736,8 +853,6 @@ impl ToSimValueWithType for BitSlice { } impl<'a, This: ?Sized + ToSimValue> ToSimValue for &'a This { - type Type = This::Type; - fn to_sim_value(&self) -> SimValue { This::to_sim_value(self) } @@ -750,8 +865,6 @@ impl, T: Type> ToSimValueWithType for &' } impl ToSimValue for &'_ mut This { - type Type = This::Type; - fn to_sim_value(&self) -> SimValue { This::to_sim_value(self) } @@ -764,8 +877,6 @@ impl, T: Type> ToSimValueWithType for &' } impl ToSimValue for Arc { - type Type = This::Type; - fn to_sim_value(&self) -> SimValue { This::arc_to_sim_value(self) } @@ -786,7 +897,6 @@ impl, T: Type> ToSimValueWithType for Ar impl ToSimValue for crate::intern::Interned { - type Type = This::Type; fn to_sim_value(&self) -> SimValue { This::to_sim_value(self) } @@ -801,8 +911,6 @@ impl + Send + Sync + 'static, T: Type> ToSi } impl ToSimValue for Box { - type Type = This::Type; - fn to_sim_value(&self) -> SimValue { This::to_sim_value(self) } @@ -845,8 +953,6 @@ impl, T: Type> ToSimValueWithType> for [ } impl> ToSimValue for [Element] { - type Type = Array; - #[track_caller] fn to_sim_value(&self) -> SimValue { SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) @@ -882,8 +988,6 @@ impl, const N: usize> ToSimValue for [Elem where ConstUsize: KnownSize, { - type Type = Array; - fn to_sim_value(&self) -> SimValue { SimValue::from_array_elements(StaticType::TYPE, self) } @@ -937,8 +1041,6 @@ impl, T: Type> ToSimValueWithType> for V } impl> ToSimValue for Vec { - type Type = Array; - fn to_sim_value(&self) -> SimValue { SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) } @@ -979,8 +1081,6 @@ impl, T: Type> ToSimValueWithType> for B } impl> ToSimValue for Box<[Element]> { - type Type = Array; - fn to_sim_value(&self) -> SimValue { SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) } @@ -1010,11 +1110,10 @@ impl> ToSimValueWithType ToSimValue for Expr { - type Type = T; #[track_caller] fn to_sim_value(&self) -> SimValue { SimValue::from_bitslice( - Expr::ty(*self), + self.ty(), &crate::expr::ToLiteralBits::to_literal_bits(self) .expect("must be a literal expression"), ) @@ -1034,8 +1133,6 @@ macro_rules! impl_to_sim_value_for_bool_like { } impl ToSimValue for bool { - type Type = Bool; - fn to_sim_value(&self) -> SimValue { SimValue::from_value(Bool, *self) } @@ -1073,10 +1170,8 @@ impl ToSimValueWithType for bool { } macro_rules! impl_to_sim_value_for_primitive_int { - ($prim:ident) => { + ($prim:ty) => { impl ToSimValue for $prim { - type Type = <$prim as ToExpr>::Type; - #[track_caller] fn to_sim_value( &self, @@ -1087,15 +1182,15 @@ macro_rules! impl_to_sim_value_for_primitive_int { forward_to_sim_value_with_type!([] $prim); - impl ToSimValueWithType<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { + impl ToSimValueWithType<<<$prim as ValueType>::Type as IntType>::Dyn> for $prim { #[track_caller] fn to_sim_value_with_type( &self, - ty: <<$prim as ToExpr>::Type as IntType>::Dyn, - ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { + ty: <<$prim as ValueType>::Type as IntType>::Dyn, + ) -> SimValue<<<$prim as ValueType>::Type as IntType>::Dyn> { SimValue::from_value( ty, - <<$prim as ToExpr>::Type as Type>::SimValue::from(*self).as_dyn_int(), + <<$prim as ValueType>::Type as Type>::SimValue::from(*self).as_dyn_int(), ) } } @@ -1103,7 +1198,7 @@ macro_rules! impl_to_sim_value_for_primitive_int { impl ToSimValueWithType for $prim { #[track_caller] fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); + let ty: <<$prim as ValueType>::Type as IntType>::Dyn = Type::from_canonical(ty); SimValue::into_canonical(self.to_sim_value_with_type(ty)) } } @@ -1122,12 +1217,22 @@ impl_to_sim_value_for_primitive_int!(i32); impl_to_sim_value_for_primitive_int!(i64); impl_to_sim_value_for_primitive_int!(i128); impl_to_sim_value_for_primitive_int!(isize); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); +impl_to_sim_value_for_primitive_int!(NonZero); macro_rules! impl_to_sim_value_for_int_value { ($IntValue:ident, $Int:ident, $IntType:ident) => { impl ToSimValue for $IntValue { - type Type = $IntType; - fn to_sim_value(&self) -> SimValue { SimValue::from_value(self.ty(), self.clone()) } @@ -1488,8 +1593,6 @@ impl ToSimValueWithType> for SimOnlyValue { } impl ToSimValue for DynSimOnlyValue { - type Type = DynSimOnly; - fn to_sim_value(&self) -> SimValue { SimValue::from_value(self.ty(), self.clone()) } @@ -1499,15 +1602,22 @@ impl ToSimValue for DynSimOnlyValue { } } -impl ToSimValue for SimOnlyValue { +impl ValueType for SimOnlyValue { type Type = SimOnly; + type ValueCategory = ValueCategoryValue; + fn ty(&self) -> Self::Type { + SimOnly::new() + } +} + +impl ToSimValue for SimOnlyValue { fn to_sim_value(&self) -> SimValue { - SimValue::from_value(Default::default(), self.clone()) + SimValue::from_value(self.ty(), self.clone()) } fn into_sim_value(self) -> SimValue { - SimValue::from_value(Default::default(), self) + SimValue::from_value(self.ty(), self) } } 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 3df80a8e..2424c03f 100644 --- a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs +++ b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs @@ -3,6 +3,7 @@ //! `unsafe` parts of [`DynSimOnlyValue`] +use crate::expr::{ValueType, value_category::ValueCategoryValue}; use serde::{Serialize, de::DeserializeOwned}; use std::{ any::{self, TypeId}, @@ -295,10 +296,16 @@ impl From> for DynSimOnlyValue { } } -impl DynSimOnlyValue { - pub fn ty(&self) -> DynSimOnly { +impl ValueType for DynSimOnlyValue { + type Type = DynSimOnly; + type ValueCategory = ValueCategoryValue; + + fn ty(&self) -> Self::Type { self.0.ty() } +} + +impl DynSimOnlyValue { pub fn type_id(&self) -> TypeId { self.0.type_id_dyn() } diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index d9ea6b27..76c09555 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -11,7 +11,7 @@ use crate::{ intern::{Intern, Interned}, phantom_const::PhantomConst, reset::{AsyncReset, Reset, SyncReset}, - sim::value::{DynSimOnlyValue, DynSimOnly, SimValue, ToSimValueWithType}, + sim::value::{DynSimOnly, DynSimOnlyValue, SimValue, ToSimValueWithType}, source_location::SourceLocation, util::{ConstUsize, slice_range, try_slice_range}, }; diff --git a/crates/fayalite/src/util/ready_valid.rs b/crates/fayalite/src/util/ready_valid.rs index 057af466..f0956799 100644 --- a/crates/fayalite/src/util/ready_valid.rs +++ b/crates/fayalite/src/util/ready_valid.rs @@ -25,7 +25,7 @@ impl ReadyValid { #[hdl] pub fn firing_data(expr: impl ToExpr) -> Expr> { let expr = expr.to_expr(); - let option_ty = Expr::ty(expr).data; + let option_ty = expr.ty().data; #[hdl] let firing_data = wire(option_ty); connect(firing_data, option_ty.HdlNone()); @@ -42,7 +42,7 @@ impl ReadyValid { ) -> Expr> { let data = HdlOption::map(expr.data, f); #[hdl] - let mapped = wire(ReadyValid[Expr::ty(data).HdlSome]); + let mapped = wire(ReadyValid[data.ty().HdlSome]); connect(mapped.data, data); connect(expr.ready, mapped.ready); mapped diff --git a/crates/fayalite/src/wire.rs b/crates/fayalite/src/wire.rs index 51f8cf7d..a350d9a4 100644 --- a/crates/fayalite/src/wire.rs +++ b/crates/fayalite/src/wire.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - expr::{Expr, Flow, ToExpr}, + expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr}, intern::Interned, module::{IncompleteDeclaration, NameId, ScopedNameId, StmtDeclaration, StmtWire}, source_location::SourceLocation, @@ -16,7 +16,16 @@ pub struct Wire { ty: T, } -impl fmt::Debug for Wire { +impl ValueType for Wire { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl fmt::Debug for Wire { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Wire({:?}: ", self.name)?; self.ty.fmt(f)?; @@ -49,9 +58,6 @@ impl Wire { ty: T::from_canonical(ty), } } - pub fn ty(&self) -> T { - self.ty - } pub fn new_unchecked( scoped_name: ScopedNameId, source_location: SourceLocation, diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index a0392503..8765a4dd 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -215,7 +215,7 @@ where let o: Array = m.output(); let bytes = v.to_string().as_bytes().to_expr(); #[hdl] - let o2: Array> = m.output(Expr::ty(bytes)); + let o2: Array> = m.output(bytes.ty()); connect( o, #[hdl] diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index be4e2071..e55a5178 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -86,7 +86,7 @@ pub fn mod1() { #[hdl] let child = instance(mod1_child()); #[hdl] - let o: mod1_child = m.output(Expr::ty(child)); + let o: mod1_child = m.output(child.ty()); connect(o, child); }