diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index d9009f8..ad943ae 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -8,6 +8,7 @@ use crate::{ bundle::{BundleField, BundleType}, enum_::{EnumType, EnumVariant}, expr::{ + ops, target::{ Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, @@ -25,14 +26,8 @@ use crate::{ reset::{ResetType, ResetTypeDispatch}, }; use hashbrown::{hash_map::Entry, HashMap}; -use hashbrown::{hash_map::Entry, HashMap}; -use num_bigint::BigInt; use num_bigint::BigInt; use petgraph::unionfind::UnionFind; -use petgraph::{ - graph::{NodeIndex, UnGraph}, - unionfind::UnionFind, -}; use std::{ borrow::Borrow, fmt, @@ -921,6 +916,94 @@ fn reg_expr_run_pass( .map(|reg| match_any_reg!(reg, ExprEnum::from))) } +fn cast_bit_op( + expr: impl ToExpr, + arg: Expr, + pass_args: PassArgs<'_, P>, +) -> Result, DeduceResetsError> { + struct Dispatch<'a, T: Type, A: Type> { + expr: Expr, + arg: Expr, + _phantom: PhantomData<&'a mut ()>, + } + impl<'a, T: Type, A: Type> PassDispatch for Dispatch<'a, T, A> { + type Input = PassArgs<'a, P>; + type Output = Result, DeduceResetsError>; + + fn build_reset_graph( + self, + mut pass_args: Self::Input, + ) -> Self::Output { + Expr::canonical(self.arg).run_pass(pass_args.as_mut())?; + let (expr_resets, _) = pass_args.get_or_make_resets(self.expr, None); + let (arg_resets, _) = pass_args.get_or_make_resets(self.arg, None); + for (expr_node_index, arg_node_index) in expr_resets + .node_indexes + .into_iter() + .zip(arg_resets.node_indexes) + { + pass_args.state.reset_graph.union( + expr_node_index, + arg_node_index, + pass_args.fallback_error_source_location, + )?; + } + Ok(PassOutput(())) + } + + fn substitute_resets( + self, + mut pass_args: Self::Input, + ) -> Self::Output { + let resets = pass_args + .get_resets(self.expr) + .expect("added resets in build_reset_graph"); + let arg = Expr::canonical(self.arg).run_pass(pass_args.as_mut())?; + let ty = resets.substituted_type( + &mut pass_args.state.reset_graph, + pass_args.state.fallback_to_sync_reset, + pass_args.fallback_error_source_location, + )?; + Ok(arg.map(|arg| { + macro_rules! match_expr_ty { + ($arg:ident, $($Variant:ident),*) => { + match ty { + CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::Reset(_) => unreachable!(), + $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* + } + }; + } + macro_rules! match_arg_ty { + ($($Variant:ident),*) => { + *match Expr::ty(arg) { + CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::Reset(_) => unreachable!(), + $(CanonicalType::$Variant(_) => { + let arg = Expr::<$Variant>::from_canonical(arg); + match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) + })* + } + }; + } + match_arg_ty!(UInt, SInt, Bool, AsyncReset, SyncReset, Clock) + })) + } + } + P::dispatch( + Dispatch { + expr: expr.to_expr(), + arg, + _phantom: PhantomData, + }, + pass_args, + ) +} + impl RunPass

for ExprEnum { fn run_pass( &self, @@ -991,51 +1074,23 @@ impl RunPass

for ExprEnum { ExprEnum::CastBoolToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastUIntToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastSIntToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastBoolToSyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastUIntToSyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSIntToSyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastBoolToAsyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastUIntToAsyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSIntToAsyncReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSyncResetToBool(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSyncResetToUInt(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSyncResetToSInt(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastSyncResetToReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastAsyncResetToBool(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastAsyncResetToUInt(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastAsyncResetToSInt(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastAsyncResetToReset(expr) => { - Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) - } - ExprEnum::CastResetToBool(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastResetToUInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::CastResetToSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::CastBoolToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastUIntToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSIntToSyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastBoolToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastUIntToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSIntToAsyncReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSyncResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSyncResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSyncResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastSyncResetToReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastAsyncResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastAsyncResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastAsyncResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastAsyncResetToReset(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastResetToBool(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastResetToUInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), + ExprEnum::CastResetToSInt(expr) => cast_bit_op(expr, expr.arg(), pass_args), ExprEnum::CastBoolToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastUIntToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastSIntToClock(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1078,6 +1133,50 @@ impl RunPass

for Expr { } } +impl RunPass

for Expr> { + fn run_pass( + &self, + pass_args: PassArgs<'_, P>, + ) -> Result, DeduceResetsError> { + Ok(Expr::canonical(*self) + .run_pass(pass_args)? + .map(Expr::from_canonical)) + } +} + +impl RunPass

for Expr> { + fn run_pass( + &self, + pass_args: PassArgs<'_, P>, + ) -> Result, DeduceResetsError> { + Ok(Expr::canonical(*self) + .run_pass(pass_args)? + .map(Expr::from_canonical)) + } +} + +impl RunPass

for Expr { + fn run_pass( + &self, + pass_args: PassArgs<'_, P>, + ) -> Result, DeduceResetsError> { + Ok(Expr::canonical(*self) + .run_pass(pass_args)? + .map(Expr::from_canonical)) + } +} + +impl RunPass

for Expr { + fn run_pass( + &self, + pass_args: PassArgs<'_, P>, + ) -> Result, DeduceResetsError> { + Ok(Expr::canonical(*self) + .run_pass(pass_args)? + .map(Expr::from_canonical)) + } +} + impl RunPassDispatch for ModuleIO { fn build_reset_graph( &self, @@ -1324,6 +1423,113 @@ macro_rules! impl_run_pass_for_enum { }; } +macro_rules! impl_run_pass_for_unary_op { + ($path:path) => { + impl_run_pass_for_struct! { + #[constructor = <$path>::new(arg)] + impl[] RunPass for $path { + arg(): _, + } + } + }; +} + +impl_run_pass_for_unary_op!(ops::NotU); +impl_run_pass_for_unary_op!(ops::NotS); +impl_run_pass_for_unary_op!(ops::NotB); +impl_run_pass_for_unary_op!(ops::Neg); +impl_run_pass_for_unary_op!(ops::CastBoolToUInt); +impl_run_pass_for_unary_op!(ops::CastBoolToSInt); +impl_run_pass_for_unary_op!(ops::CastUIntToBool); +impl_run_pass_for_unary_op!(ops::CastSIntToBool); +impl_run_pass_for_unary_op!(ops::CastBoolToClock); +impl_run_pass_for_unary_op!(ops::CastUIntToClock); +impl_run_pass_for_unary_op!(ops::CastSIntToClock); +impl_run_pass_for_unary_op!(ops::CastClockToBool); +impl_run_pass_for_unary_op!(ops::CastClockToUInt); +impl_run_pass_for_unary_op!(ops::CastClockToSInt); +impl_run_pass_for_unary_op!(ops::ReduceBitAndU); +impl_run_pass_for_unary_op!(ops::ReduceBitAndS); +impl_run_pass_for_unary_op!(ops::ReduceBitOrU); +impl_run_pass_for_unary_op!(ops::ReduceBitOrS); +impl_run_pass_for_unary_op!(ops::ReduceBitXorU); +impl_run_pass_for_unary_op!(ops::ReduceBitXorS); + +macro_rules! impl_run_pass_for_binary_op { + ($path:path) => { + impl_run_pass_for_struct! { + #[constructor = <$path>::new(lhs, rhs)] + impl[] RunPass for $path { + lhs(): _, + rhs(): _, + } + } + }; +} + +impl_run_pass_for_binary_op!(ops::BitAndU); +impl_run_pass_for_binary_op!(ops::BitAndS); +impl_run_pass_for_binary_op!(ops::BitAndB); +impl_run_pass_for_binary_op!(ops::BitOrU); +impl_run_pass_for_binary_op!(ops::BitOrS); +impl_run_pass_for_binary_op!(ops::BitOrB); +impl_run_pass_for_binary_op!(ops::BitXorU); +impl_run_pass_for_binary_op!(ops::BitXorS); +impl_run_pass_for_binary_op!(ops::BitXorB); +impl_run_pass_for_binary_op!(ops::AddU); +impl_run_pass_for_binary_op!(ops::AddS); +impl_run_pass_for_binary_op!(ops::SubU); +impl_run_pass_for_binary_op!(ops::SubS); +impl_run_pass_for_binary_op!(ops::MulU); +impl_run_pass_for_binary_op!(ops::MulS); +impl_run_pass_for_binary_op!(ops::DivU); +impl_run_pass_for_binary_op!(ops::DivS); +impl_run_pass_for_binary_op!(ops::RemU); +impl_run_pass_for_binary_op!(ops::RemS); +impl_run_pass_for_binary_op!(ops::DynShlU); +impl_run_pass_for_binary_op!(ops::DynShlS); +impl_run_pass_for_binary_op!(ops::DynShrU); +impl_run_pass_for_binary_op!(ops::DynShrS); +impl_run_pass_for_binary_op!(ops::FixedShlU); +impl_run_pass_for_binary_op!(ops::FixedShlS); +impl_run_pass_for_binary_op!(ops::FixedShrU); +impl_run_pass_for_binary_op!(ops::FixedShrS); +impl_run_pass_for_binary_op!(ops::CmpLtB); +impl_run_pass_for_binary_op!(ops::CmpLeB); +impl_run_pass_for_binary_op!(ops::CmpGtB); +impl_run_pass_for_binary_op!(ops::CmpGeB); +impl_run_pass_for_binary_op!(ops::CmpEqB); +impl_run_pass_for_binary_op!(ops::CmpNeB); +impl_run_pass_for_binary_op!(ops::CmpLtU); +impl_run_pass_for_binary_op!(ops::CmpLeU); +impl_run_pass_for_binary_op!(ops::CmpGtU); +impl_run_pass_for_binary_op!(ops::CmpGeU); +impl_run_pass_for_binary_op!(ops::CmpEqU); +impl_run_pass_for_binary_op!(ops::CmpNeU); +impl_run_pass_for_binary_op!(ops::CmpLtS); +impl_run_pass_for_binary_op!(ops::CmpLeS); +impl_run_pass_for_binary_op!(ops::CmpGtS); +impl_run_pass_for_binary_op!(ops::CmpGeS); +impl_run_pass_for_binary_op!(ops::CmpEqS); +impl_run_pass_for_binary_op!(ops::CmpNeS); + +macro_rules! impl_run_pass_for_int_cast_op { + ($path:path) => { + impl_run_pass_for_struct! { + #[constructor = <$path>::new(arg, ty)] + impl[] RunPass for $path { + arg(): _, + ty(): _, + } + } + }; +} + +impl_run_pass_for_int_cast_op!(ops::CastUIntToUInt); +impl_run_pass_for_int_cast_op!(ops::CastUIntToSInt); +impl_run_pass_for_int_cast_op!(ops::CastSIntToUInt); +impl_run_pass_for_int_cast_op!(ops::CastSIntToSInt); + impl_run_pass_for_struct! { impl[] RunPass for Block { memories: _,