diff --git a/.forgejo/workflows/deps.yml b/.forgejo/workflows/deps.yml index b29723c..ffaca53 100644 --- a/.forgejo/workflows/deps.yml +++ b/.forgejo/workflows/deps.yml @@ -12,10 +12,10 @@ jobs: outputs: cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }} steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 + - uses: https://code.forgejo.org/actions/checkout@v3 with: fetch-depth: 0 - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 + - uses: https://code.forgejo.org/actions/cache/restore@v3 id: restore-deps with: path: deps @@ -58,19 +58,19 @@ jobs: - name: Get SymbiYosys if: steps.restore-deps.outputs.cache-hit != 'true' run: | - git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby + git clone --depth=1 --branch=yosys-0.45 https://github.com/YosysHQ/sby.git deps/sby - name: Build Z3 if: steps.restore-deps.outputs.cache-hit != 'true' run: | - git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3 + git clone --depth=1 --recursive --branch=z3-4.13.3 https://github.com/Z3Prover/z3.git deps/z3 (cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local) make -C deps/z3/build -j"$(nproc)" - name: Build Yosys if: steps.restore-deps.outputs.cache-hit != 'true' run: | - git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys + git clone --depth=1 --recursive --branch=0.45 https://github.com/YosysHQ/yosys.git deps/yosys make -C deps/yosys -j"$(nproc)" - - uses: https://git.libre-chip.org/mirrors/cache/save@v3 + - uses: https://code.forgejo.org/actions/cache/save@v3 if: steps.restore-deps.outputs.cache-hit != 'true' with: path: deps diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 49fb3e4..e83c668 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -9,7 +9,7 @@ jobs: runs-on: debian-12 needs: deps steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 + - uses: https://code.forgejo.org/actions/checkout@v3 with: fetch-depth: 0 - run: | @@ -41,7 +41,7 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.82.0 source "$HOME/.cargo/env" echo "$PATH" >> "$GITHUB_PATH" - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 + - uses: https://code.forgejo.org/actions/cache/restore@v3 with: path: deps key: ${{ needs.deps.outputs.cache-primary-key }} @@ -52,7 +52,7 @@ jobs: make -C deps/yosys install export PATH="$(realpath deps/firtool/bin):$PATH" echo "$PATH" >> "$GITHUB_PATH" - - uses: https://git.libre-chip.org/mirrors/rust-cache@v2 + - uses: https://github.com/Swatinem/rust-cache@v2 with: save-if: ${{ github.ref == 'refs/heads/master' }} - run: cargo test diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index b0fe498..79326e2 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -83,7 +83,6 @@ impl ParsedBundle { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq: _, } = options.body; let mut fields = match fields { syn::Fields::Named(fields) => fields, @@ -438,7 +437,6 @@ impl ToTokens for ParsedBundle { custom_bounds: _, no_static, no_runtime_generics, - cmp_eq, } = &options.body; let target = get_target(target, ident); let mut item_attrs = attrs.clone(); @@ -767,69 +765,6 @@ impl ToTokens for ParsedBundle { } } .to_tokens(tokens); - if let Some((cmp_eq,)) = cmp_eq { - let mut where_clause = - Generics::from(generics) - .where_clause - .unwrap_or_else(|| syn::WhereClause { - where_token: Token![where](span), - predicates: Punctuated::new(), - }); - let mut fields_cmp_eq = vec![]; - let mut fields_cmp_ne = vec![]; - for field in fields.named() { - let field_ident = field.ident(); - let field_ty = field.ty(); - where_clause - .predicates - .push(parse_quote_spanned! {cmp_eq.span=> - #field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty> - }); - fields_cmp_eq.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident) - }); - fields_cmp_ne.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident) - }); - } - let cmp_eq_body; - let cmp_ne_body; - if fields_len == 0 { - cmp_eq_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&true) - }; - cmp_ne_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&false) - }; - } else { - cmp_eq_body = quote_spanned! {span=> - #(#fields_cmp_eq)&* - }; - cmp_ne_body = quote_spanned! {span=> - #(#fields_cmp_ne)|* - }; - }; - quote_spanned! {span=> - #[automatically_derived] - impl #impl_generics ::fayalite::expr::ops::ExprPartialEq for #target #type_generics - #where_clause - { - fn cmp_eq( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_eq_body - } - fn cmp_ne( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_ne_body - } - } - } - .to_tokens(tokens); - } if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { let static_generics = generics.clone().for_static_type(); let (static_impl_generics, static_type_generics, static_where_clause) = diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index 9174566..1d16177 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -155,11 +155,7 @@ impl ParsedEnum { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq, } = options.body; - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums"); - } attrs.retain(|attr| { if attr.path().is_ident("repr") { errors.error(attr, "#[repr] is not supported on #[hdl] enums"); @@ -215,7 +211,6 @@ impl ToTokens for ParsedEnum { custom_bounds: _, no_static, no_runtime_generics, - cmp_eq: _, // TODO: implement cmp_eq for enums } = &options.body; let target = get_target(target, ident); let mut struct_attrs = attrs.clone(); diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs index 97501e7..e5d5f7b 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs @@ -49,14 +49,10 @@ impl ParsedTypeAlias { custom_bounds, no_static, no_runtime_generics: _, - cmp_eq, } = options.body; if let Some((no_static,)) = no_static { errors.error(no_static, "no_static is not valid on type aliases"); } - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "cmp_eq is not valid on type aliases"); - } let generics = if custom_bounds.is_some() { MaybeParsed::Unrecognized(generics) } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) { @@ -99,7 +95,6 @@ impl ToTokens for ParsedTypeAlias { custom_bounds: _, no_static: _, no_runtime_generics, - cmp_eq: _, } = &options.body; let target = get_target(target, ident); let mut type_attrs = attrs.clone(); diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs index 2da0915..6193dc3 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -26,7 +26,6 @@ crate::options! { CustomBounds(custom_bounds), NoStatic(no_static), NoRuntimeGenerics(no_runtime_generics), - CmpEq(cmp_eq), } } @@ -2070,16 +2069,11 @@ macro_rules! impl_bounds { $( $Variant:ident, )* - $( - #[unknown] - $Unknown:ident, - )? } ) => { #[derive(Clone, Debug)] $vis enum $enum_type { $($Variant(known_items::$Variant),)* - $($Unknown(syn::TypeParamBound),)? } $(impl From for $enum_type { @@ -2092,54 +2086,28 @@ macro_rules! impl_bounds { fn to_tokens(&self, tokens: &mut TokenStream) { match self { $(Self::$Variant(v) => v.to_tokens(tokens),)* - $(Self::$Unknown(v) => v.to_tokens(tokens),)? } } } impl $enum_type { $vis fn parse_path(path: Path) -> Result { - #![allow(unreachable_code)] $(let path = match known_items::$Variant::parse_path(path) { Ok(v) => return Ok(Self::$Variant(v)), Err(path) => path, };)* - $(return Ok(Self::$Unknown(syn::TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - }.into()));)? Err(path) } - $vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> Result { - #![allow(unreachable_code)] - if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound { - if let syn::TraitBound { - paren_token: _, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path: _, - } = trait_bound { - match Self::parse_path(trait_bound.path) { - Ok(retval) => return Ok(retval), - Err(path) => trait_bound.path = path, - } - } - type_param_bound = trait_bound.into(); - } - $(return Ok(Self::$Unknown(type_param_bound));)? - Err(type_param_bound) - } } impl Parse for $enum_type { fn parse(input: ParseStream) -> syn::Result { - Self::parse_type_param_bound(input.parse()?) - .map_err(|type_param_bound| syn::Error::new_spanned( - type_param_bound, + Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| { + syn::Error::new_spanned( + path, format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), - )) + ) + }) } } @@ -2147,7 +2115,6 @@ macro_rules! impl_bounds { #[allow(non_snake_case)] $vis struct $struct_type { $($vis $Variant: Option,)* - $($vis $Unknown: Vec,)? } impl ToTokens for $struct_type { @@ -2159,63 +2126,42 @@ macro_rules! impl_bounds { separator = Some(::default()); v.to_tokens(tokens); })* - $(for v in &self.$Unknown { - separator.to_tokens(tokens); - separator = Some(::default()); - v.to_tokens(tokens); - })* } } const _: () = { #[derive(Clone, Debug)] - #[allow(non_snake_case)] - $vis struct Iter { - $($Variant: Option,)* - $($Unknown: std::vec::IntoIter,)? - } + $vis struct Iter($vis $struct_type); impl IntoIterator for $struct_type { type Item = $enum_type; type IntoIter = Iter; fn into_iter(self) -> Self::IntoIter { - Iter { - $($Variant: self.$Variant,)* - $($Unknown: self.$Unknown.into_iter(),)? - } + Iter(self) } } impl Iterator for Iter { type Item = $enum_type; + fn next(&mut self) -> Option { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { return Some($enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$Unknown.next() { - return Some($enum_type::$Unknown(value)); - } - )? None } #[allow(unused_mut, unused_variables)] fn fold B>(mut self, mut init: B, mut f: F) -> B { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { init = f(init, $enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$Unknown.next() { - init = f(init, $enum_type::$Unknown(value)); - } - )? init } } @@ -2227,9 +2173,6 @@ macro_rules! impl_bounds { $($enum_type::$Variant(v) => { self.$Variant = Some(v); })* - $($enum_type::$Unknown(v) => { - self.$Unknown.push(v); - })? }); } } @@ -2248,7 +2191,6 @@ macro_rules! impl_bounds { $(if let Some(v) = v.$Variant { self.$Variant = Some(v); })* - $(self.$Unknown.extend(v.$Unknown);)* }); } } @@ -2302,8 +2244,6 @@ impl_bounds! { Size, StaticType, Type, - #[unknown] - Unknown, } } @@ -2317,8 +2257,6 @@ impl_bounds! { ResetType, StaticType, Type, - #[unknown] - Unknown, } } @@ -2332,7 +2270,6 @@ impl From for ParsedBound { ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v), ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v), ParsedTypeBound::Type(v) => ParsedBound::Type(v), - ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v), } } } @@ -2347,7 +2284,6 @@ impl From for ParsedBounds { ResetType, StaticType, Type, - Unknown, } = value; Self { BoolOrIntType, @@ -2359,7 +2295,6 @@ impl From for ParsedBounds { Size: None, StaticType, Type, - Unknown, } } } @@ -2395,7 +2330,6 @@ impl ParsedTypeBound { ParsedTypeBound::Type(known_items::Type(span)), ]), Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]), - Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]), } } } @@ -2430,7 +2364,6 @@ impl From for ParsedBounds { Size, StaticType: None, Type: None, - Unknown: vec![], } } } @@ -2458,7 +2391,6 @@ impl ParsedBounds { fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory { let mut type_bounds = None; let mut size_type_bounds = None; - let mut unknown_bounds = vec![]; self.into_iter().for_each(|bound| match bound.categorize() { ParsedBoundCategory::Type(bound) => { type_bounds @@ -2470,37 +2402,15 @@ impl ParsedBounds { .get_or_insert_with(ParsedSizeTypeBounds::default) .extend([bound]); } - ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound), }); - match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) { - (None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds { + match (type_bounds, size_type_bounds) { + (None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds { Type: Some(known_items::Type(span)), ..Default::default() }), - (None, None, false) => { - errors.error( - unknown_bounds.remove(0), - "unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds", - ); - ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..Default::default() - }) - } - (None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds), - (None, Some(bounds), false) => { - // TODO: implement - errors.error( - unknown_bounds.remove(0), - "unknown bounds with `Size` bounds are not implemented", - ); - ParsedBoundsCategory::SizeType(bounds) - } - (Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..bounds - }), - (Some(type_bounds), Some(size_type_bounds), _) => { + (None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds), + (Some(bounds), None) => ParsedBoundsCategory::Type(bounds), + (Some(type_bounds), Some(size_type_bounds)) => { errors.error( size_type_bounds .Size @@ -2517,7 +2427,6 @@ impl ParsedBounds { pub(crate) enum ParsedBoundCategory { Type(ParsedTypeBound), SizeType(ParsedSizeTypeBound), - Unknown(syn::TypeParamBound), } impl ParsedBound { @@ -2532,14 +2441,12 @@ impl ParsedBound { Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)), Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)), Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)), - Self::Unknown(v) => ParsedBoundCategory::Unknown(v), } } fn implied_bounds(self) -> ParsedBounds { match self.categorize() { ParsedBoundCategory::Type(v) => v.implied_bounds().into(), ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(), - ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]), } } } @@ -3418,7 +3325,7 @@ impl ParsedGenerics { | ParsedTypeBound::EnumType(_) | ParsedTypeBound::IntType(_) | ParsedTypeBound::ResetType(_) => { - errors.error(bound, "bounds on mask types are not implemented"); + errors.error(bound, "bound on mask type not implemented"); } ParsedTypeBound::StaticType(bound) => { if bounds.StaticType.is_none() { @@ -3430,12 +3337,6 @@ impl ParsedGenerics { } } ParsedTypeBound::Type(_) => {} - ParsedTypeBound::Unknown(_) => { - errors.error( - bound, - "unknown bounds on mask types are not implemented", - ); - } } } bounds.add_implied_bounds(); diff --git a/crates/fayalite-proc-macros-impl/src/lib.rs b/crates/fayalite-proc-macros-impl/src/lib.rs index 5fe3ae8..6ba177b 100644 --- a/crates/fayalite-proc-macros-impl/src/lib.rs +++ b/crates/fayalite-proc-macros-impl/src/lib.rs @@ -72,14 +72,13 @@ mod kw { custom_keyword!(cfg); custom_keyword!(cfg_attr); custom_keyword!(clock_domain); - custom_keyword!(cmp_eq); custom_keyword!(connect_inexact); custom_keyword!(custom_bounds); custom_keyword!(flip); custom_keyword!(hdl); custom_keyword!(hdl_module); - custom_keyword!(incomplete_wire); custom_keyword!(input); + custom_keyword!(incomplete_wire); custom_keyword!(instance); custom_keyword!(m); custom_keyword!(memory); diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 0d9b63f..f617f91 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -2,11 +2,8 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq}, - CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr, - }, - int::{Bool, DynSize, KnownSize, Size, SizeType, DYN_SIZE}, + expr::{ops::ArrayIndex, Expr, ToExpr}, + int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE}, intern::{Intern, Interned, LazyInterned}, module::transform::visit::{Fold, Folder, Visit, Visitor}, source_location::SourceLocation, @@ -15,7 +12,7 @@ use crate::{ }, util::ConstUsize, }; -use std::{iter::FusedIterator, ops::Index}; +use std::ops::Index; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct ArrayType { @@ -151,8 +148,10 @@ impl Type for ArrayType { this: Expr, source_location: SourceLocation, ) -> Self::MatchVariantsIter { + let base = Expr::as_dyn_array(this); + let base_ty = Expr::ty(base); let _ = source_location; - let retval = Vec::from_iter(this); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); std::iter::once(MatchVariantWithoutScope( Len::ArrayMatch::::try_from(retval) .ok() @@ -185,7 +184,9 @@ impl Type for ArrayType { impl TypeWithDeref for ArrayType { fn expr_deref(this: &Expr) -> &Self::MatchVariant { - let retval = Vec::from_iter(*this); + let base = Expr::as_dyn_array(*this); + let base_ty = Expr::ty(base); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); Interned::into_inner(Intern::intern_sized( Len::ArrayMatch::::try_from(retval) .ok() @@ -217,131 +218,3 @@ impl Index for ArrayWithoutLen { Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) } } - -impl ExprPartialEq> for ArrayType -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()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_eq(r)) - .collect::>>() - .cast_to_bits() - .all_one_bits() - } - - 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()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_ne(r)) - .collect::>>() - .cast_to_bits() - .any_one_bits() - } -} - -impl ExprIntoIterator for ArrayType { - type Item = T; - type ExprIntoIter = ExprArrayIter; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter { - ExprArrayIter { - base: e, - indexes: 0..Expr::ty(e).len(), - } - } -} - -#[derive(Clone, Debug)] -pub struct ExprArrayIter { - base: Expr>, - indexes: std::ops::Range, -} - -impl ExprArrayIter { - pub fn base(&self) -> Expr> { - self.base - } - pub fn indexes(&self) -> std::ops::Range { - self.indexes.clone() - } -} - -impl Iterator for ExprArrayIter { - type Item = Expr; - - fn next(&mut self) -> Option { - self.indexes.next().map(|i| self.base[i]) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } - - fn count(self) -> usize { - self.indexes.count() - } - - fn last(mut self) -> Option { - self.next_back() - } - - fn nth(&mut self, n: usize) -> Option { - self.indexes.nth(n).map(|i| self.base[i]) - } - - fn fold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.fold(init, |b, i| f(b, self.base[i])) - } -} - -impl DoubleEndedIterator for ExprArrayIter { - fn next_back(&mut self) -> Option { - self.indexes.next_back().map(|i| self.base[i]) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.indexes.nth_back(n).map(|i| self.base[i]) - } - - fn rfold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.rfold(init, |b, i| f(b, self.base[i])) - } -} - -impl ExactSizeIterator for ExprArrayIter { - fn len(&self) -> usize { - self.indexes.len() - } -} - -impl FusedIterator for ExprArrayIter {} - -impl ExprFromIterator> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - ArrayLiteral::new( - A::TYPE, - iter.into_iter().map(|v| Expr::canonical(v)).collect(), - ) - .to_expr() - } -} - -impl<'a, A: StaticType> ExprFromIterator<&'a Expr> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - iter.into_iter().copied().collect() - } -} diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index 9807b92..995510e 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -2,11 +2,7 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ArrayLiteral, BundleLiteral, ExprPartialEq}, - CastToBits, Expr, ReduceBits, ToExpr, - }, - int::{Bool, DynSize}, + expr::{ops::BundleLiteral, Expr, ToExpr}, intern::{Intern, Interned}, sim::{SimValue, ToSimValue}, source_location::SourceLocation, @@ -329,19 +325,7 @@ macro_rules! impl_tuple_builder_fields { } macro_rules! impl_tuples { - ( - [$({ - #[ - num = $num:tt, - field = $field:ident, - ty = $ty_var:ident: $Ty:ident, - lhs = $lhs_var:ident: $Lhs:ident, - rhs = $rhs_var:ident: $Rhs:ident - ] - $var:ident: $T:ident - })*] - [] - ) => { + ([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty:ident] $var:ident: $T:ident})*] []) => { impl_tuple_builder_fields! { {} [$({ @@ -514,29 +498,6 @@ macro_rules! impl_tuples { Self::into_sim_value(*self, ty) } } - impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { - fn cmp_eq(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .all_one_bits() - } - - fn cmp_ne(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .any_one_bits() - } - } }; ([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => { impl_tuples!([$($lhs)*] []); @@ -546,18 +507,18 @@ macro_rules! impl_tuples { impl_tuples! { [] [ - {#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0} - {#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1} - {#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2} - {#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3} - {#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4} - {#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5} - {#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6} - {#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7} - {#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8} - {#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9} - {#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10} - {#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11} + {#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0} + {#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1} + {#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2} + {#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3} + {#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4} + {#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5} + {#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6} + {#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7} + {#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8} + {#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9} + {#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10} + {#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11} ] } diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 70c58c0..2ed0b8e 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -2,10 +2,7 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - ops::{ExprPartialEq, VariantAccess}, - Expr, ToExpr, - }, + expr::{ops::VariantAccess, Expr, ToExpr}, hdl, int::Bool, intern::{Intern, Interned}, @@ -363,60 +360,6 @@ pub enum HdlOption { HdlSome(T), } -impl, Rhs: Type> ExprPartialEq> for HdlOption { - #[hdl] - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_eq = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)), - HdlNone => connect(cmp_eq, false), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_eq, false), - HdlNone => connect(cmp_eq, true), - } - } - } - cmp_eq - } - - #[hdl] - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_ne = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)), - HdlNone => connect(cmp_ne, true), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_ne, true), - HdlNone => connect(cmp_ne, false), - } - } - } - cmp_ne - } -} - #[allow(non_snake_case)] pub fn HdlNone() -> Expr> { HdlOption[T::TYPE].HdlNone() diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index c502fd5..15c195e 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -2708,47 +2708,3 @@ impl ToExpr for Uninit { } } } - -pub trait ExprIntoIterator: Type { - type Item: Type; - type ExprIntoIter: Iterator>; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter; -} - -impl IntoIterator for Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(self) - } -} - -impl IntoIterator for &'_ Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -impl IntoIterator for &'_ mut Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -pub trait ExprFromIterator: Type { - fn expr_from_iter>(iter: T) -> Expr; -} - -impl, A> FromIterator for Expr { - fn from_iter>(iter: T) -> Self { - This::expr_from_iter(iter) - } -} diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 66fc921..fadc7af 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -29,5 +29,4 @@ pub use misc::{ }; pub mod job_server; -pub mod prefix_sum; pub mod ready_valid; diff --git a/crates/fayalite/src/util/prefix_sum.rs b/crates/fayalite/src/util/prefix_sum.rs deleted file mode 100644 index 758d89c..0000000 --- a/crates/fayalite/src/util/prefix_sum.rs +++ /dev/null @@ -1,839 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -// code derived from: -// https://web.archive.org/web/20250303054010/https://git.libre-soc.org/?p=nmutil.git;a=blob;f=src/nmutil/prefix_sum.py;hb=effeb28e5848392adddcdad1f6e7a098f2a44c9c - -use crate::intern::{Intern, Interned, Memoize}; -use std::{borrow::Cow, num::NonZeroUsize}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct PrefixSumOp { - pub lhs_index: usize, - pub rhs_and_dest_index: NonZeroUsize, - pub row: u32, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[non_exhaustive] -pub struct DiagramConfig { - pub space: Cow<'static, str>, - pub vertical_bar: Cow<'static, str>, - pub plus: Cow<'static, str>, - pub slant: Cow<'static, str>, - pub connect: Cow<'static, str>, - pub no_connect: Cow<'static, str>, - pub padding: usize, -} - -impl DiagramConfig { - pub const fn new() -> Self { - Self { - space: Cow::Borrowed(" "), - vertical_bar: Cow::Borrowed("|"), - plus: Cow::Borrowed("\u{2295}"), // ⊕ - slant: Cow::Borrowed(r"\"), - connect: Cow::Borrowed("\u{25CF}"), // ● - no_connect: Cow::Borrowed("X"), - padding: 1, - } - } - pub fn draw(self, ops: impl IntoIterator, item_count: usize) -> String { - #[derive(Copy, Clone, Debug)] - struct DiagramCell { - slant: bool, - plus: bool, - tee: bool, - } - let mut ops_by_row: Vec> = Vec::new(); - let mut last_row = 0; - ops.into_iter().for_each(|op| { - assert!( - op.lhs_index < op.rhs_and_dest_index.get(), - "invalid PrefixSumOp! lhs_index must be less \ - than rhs_and_dest_index: {op:?}", - ); - assert!( - op.row >= last_row, - "invalid PrefixSumOp! row must \ - not decrease (row last was: {last_row}): {op:?}", - ); - let ops = if op.row > last_row || ops_by_row.is_empty() { - ops_by_row.push(vec![]); - ops_by_row.last_mut().expect("just pushed") - } else { - ops_by_row - .last_mut() - .expect("just checked if ops_by_row is empty") - }; - if let Some(last) = ops.last() { - assert!( - op.rhs_and_dest_index < last.rhs_and_dest_index, - "invalid PrefixSumOp! rhs_and_dest_index must strictly \ - decrease in a row:\nthis op: {op:?}\nlast op: {last:?}", - ); - } - ops.push(op); - last_row = op.row; - }); - let blank_row = || { - vec![ - DiagramCell { - slant: false, - plus: false, - tee: false - }; - item_count - ] - }; - let mut cells = vec![blank_row()]; - for ops in ops_by_row { - let max_distance = ops - .iter() - .map( - |&PrefixSumOp { - lhs_index, - rhs_and_dest_index, - .. - }| { rhs_and_dest_index.get() - lhs_index }, - ) - .max() - .expect("ops is known to be non-empty"); - cells.extend((0..max_distance).map(|_| blank_row())); - for op in ops { - let mut y = cells.len() - 1; - assert!( - op.rhs_and_dest_index.get() < item_count, - "invalid PrefixSumOp! rhs_and_dest_index must be \ - less than item_count ({item_count}): {op:?}", - ); - let mut x = op.rhs_and_dest_index.get(); - cells[y][x].plus = true; - x -= 1; - y -= 1; - while op.lhs_index < x { - cells[y][x].slant = true; - x -= 1; - y -= 1; - } - cells[y][x].tee = true; - } - } - let mut retval = String::new(); - let mut row_text = vec![String::new(); 2 * self.padding + 1]; - for cells_row in cells { - for cell in cells_row { - // top padding - for y in 0..self.padding { - // top left padding - for x in 0..self.padding { - row_text[y] += if x == y && (cell.plus || cell.slant) { - &self.slant - } else { - &self.space - }; - } - // top vertical bar - row_text[y] += &self.vertical_bar; - // top right padding - for _ in 0..self.padding { - row_text[y] += &self.space; - } - } - // center left padding - for _ in 0..self.padding { - row_text[self.padding] += &self.space; - } - // center - row_text[self.padding] += if cell.plus { - &self.plus - } else if cell.tee { - &self.connect - } else if cell.slant { - &self.no_connect - } else { - &self.vertical_bar - }; - // center right padding - for _ in 0..self.padding { - row_text[self.padding] += &self.space; - } - let bottom_padding_start = self.padding + 1; - let bottom_padding_last = self.padding * 2; - // bottom padding - for y in bottom_padding_start..=bottom_padding_last { - // bottom left padding - for _ in 0..self.padding { - row_text[y] += &self.space; - } - // bottom vertical bar - row_text[y] += &self.vertical_bar; - // bottom right padding - for x in bottom_padding_start..=bottom_padding_last { - row_text[y] += if x == y && (cell.tee || cell.slant) { - &self.slant - } else { - &self.space - }; - } - } - } - for line in &mut row_text { - retval += line.trim_end(); - retval += "\n"; - line.clear(); - } - } - retval - } -} - -impl Default for DiagramConfig { - fn default() -> Self { - Self::new() - } -} - -impl PrefixSumOp { - pub fn diagram(ops: impl IntoIterator, item_count: usize) -> String { - Self::diagram_with_config(ops, item_count, DiagramConfig::new()) - } - pub fn diagram_with_config( - ops: impl IntoIterator, - item_count: usize, - config: DiagramConfig, - ) -> String { - config.draw(ops, item_count) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum PrefixSumAlgorithm { - /// Uses the algorithm from: - /// https://en.wikipedia.org/wiki/Prefix_sum#Algorithm_1:_Shorter_span,_more_parallel - LowLatency, - /// Uses the algorithm from: - /// https://en.wikipedia.org/wiki/Prefix_sum#Algorithm_2:_Work-efficient - WorkEfficient, -} - -impl PrefixSumAlgorithm { - fn ops_impl(self, item_count: usize) -> Vec { - let mut retval = Vec::new(); - let mut distance = 1; - let mut row = 0; - while distance < item_count { - let double_distance = distance - .checked_mul(2) - .expect("prefix-sum item_count is too big"); - let (start, step) = match self { - Self::LowLatency => (distance, 1), - Self::WorkEfficient => (double_distance - 1, double_distance), - }; - for rhs_and_dest_index in (start..item_count).step_by(step).rev() { - let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else { - unreachable!(); - }; - let lhs_index = rhs_and_dest_index.get() - distance; - retval.push(PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row, - }); - } - distance = double_distance; - row += 1; - } - match self { - Self::LowLatency => {} - Self::WorkEfficient => { - distance /= 2; - while distance >= 1 { - let start = distance - .checked_mul(3) - .expect("prefix-sum item_count is too big") - - 1; - for rhs_and_dest_index in (start..item_count).step_by(distance * 2).rev() { - let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else { - unreachable!(); - }; - let lhs_index = rhs_and_dest_index.get() - distance; - retval.push(PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row, - }); - } - row += 1; - distance /= 2; - } - } - } - retval - } - pub fn ops(self, item_count: usize) -> Interned<[PrefixSumOp]> { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct MyMemoize(PrefixSumAlgorithm); - impl Memoize for MyMemoize { - type Input = usize; - type InputOwned = usize; - type Output = Interned<[PrefixSumOp]>; - - fn inner(self, item_count: &Self::Input) -> Self::Output { - Intern::intern_owned(self.0.ops_impl(*item_count)) - } - } - MyMemoize(self).get_owned(item_count) - } - pub fn run(self, items: impl IntoIterator, f: impl FnMut(&T, &T) -> T) -> Vec { - let mut items = Vec::from_iter(items); - self.run_on_slice(&mut items, f); - items - } - pub fn run_on_slice(self, items: &mut [T], mut f: impl FnMut(&T, &T) -> T) -> &mut [T] { - self.ops(items.len()).into_iter().for_each( - |PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row: _, - }| { - items[rhs_and_dest_index.get()] = - f(&items[lhs_index], &items[rhs_and_dest_index.get()]); - }, - ); - items - } - pub fn filtered_ops( - self, - item_live_out_flags: impl IntoIterator, - ) -> Vec { - let mut item_live_out_flags = Vec::from_iter(item_live_out_flags); - let prefix_sum_ops = self.ops(item_live_out_flags.len()); - let mut ops_live_flags = vec![false; prefix_sum_ops.len()]; - for ( - op_index, - &PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row: _, - }, - ) in prefix_sum_ops.iter().enumerate().rev() - { - let live = item_live_out_flags[rhs_and_dest_index.get()]; - item_live_out_flags[lhs_index] |= live; - ops_live_flags[op_index] = live; - } - prefix_sum_ops - .into_iter() - .zip(ops_live_flags) - .filter_map(|(op, live)| live.then_some(op)) - .collect() - } - pub fn reduce_ops(self, item_count: usize) -> Interned<[PrefixSumOp]> { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct MyMemoize(PrefixSumAlgorithm); - impl Memoize for MyMemoize { - type Input = usize; - type InputOwned = usize; - type Output = Interned<[PrefixSumOp]>; - - fn inner(self, item_count: &Self::Input) -> Self::Output { - let mut item_live_out_flags = vec![false; *item_count]; - let Some(last_item_live_out_flag) = item_live_out_flags.last_mut() else { - return Interned::default(); - }; - *last_item_live_out_flag = true; - Intern::intern_owned(self.0.filtered_ops(item_live_out_flags)) - } - } - MyMemoize(self).get_owned(item_count) - } -} - -pub fn reduce_ops(item_count: usize) -> Interned<[PrefixSumOp]> { - PrefixSumAlgorithm::LowLatency.reduce_ops(item_count) -} - -pub fn reduce(items: impl IntoIterator, mut f: impl FnMut(T, T) -> T) -> Option { - let mut items: Vec<_> = items.into_iter().map(Some).collect(); - for op in reduce_ops(items.len()) { - let (Some(lhs), Some(rhs)) = ( - items[op.lhs_index].take(), - items[op.rhs_and_dest_index.get()].take(), - ) else { - unreachable!(); - }; - items[op.rhs_and_dest_index.get()] = Some(f(lhs, rhs)); - } - items.last_mut().and_then(Option::take) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn input_strings() -> [String; 9] { - std::array::from_fn(|i| String::from_utf8(vec![b'a' + i as u8]).unwrap()) - } - - #[test] - fn test_prefix_sum_strings() { - let input = input_strings(); - let expected: Vec = input - .iter() - .scan(String::new(), |l, r| { - *l += r; - Some(l.clone()) - }) - .collect(); - println!("expected: {expected:?}"); - assert_eq!( - *PrefixSumAlgorithm::WorkEfficient - .run_on_slice(&mut input.clone(), |l, r| l.to_string() + r), - *expected - ); - assert_eq!( - *PrefixSumAlgorithm::LowLatency - .run_on_slice(&mut input.clone(), |l, r| l.to_string() + r), - *expected - ); - } - - #[test] - fn test_reduce_string() { - let input = input_strings(); - let expected = input.clone().into_iter().reduce(|l, r| l + &r); - assert_eq!(reduce(input, |l, r| l + &r), expected); - } - - fn op(lhs_index: usize, rhs_and_dest_index: usize, row: u32) -> PrefixSumOp { - PrefixSumOp { - lhs_index, - rhs_and_dest_index: NonZeroUsize::new(rhs_and_dest_index).expect("should be non-zero"), - row, - } - } - - #[test] - fn test_reduce_ops_9() { - let expected = vec![ - op(7, 8, 0), - op(5, 6, 0), - op(3, 4, 0), - op(1, 2, 0), - op(6, 8, 1), - op(2, 4, 1), - op(4, 8, 2), - op(0, 8, 3), - ]; - println!("expected: {expected:#?}"); - let ops = reduce_ops(9); - println!("ops: {ops:#?}"); - assert_eq!(*ops, *expected); - } - - #[test] - fn test_reduce_ops_8() { - let expected = vec![ - op(6, 7, 0), - op(4, 5, 0), - op(2, 3, 0), - op(0, 1, 0), - op(5, 7, 1), - op(1, 3, 1), - op(3, 7, 2), - ]; - println!("expected: {expected:#?}"); - let ops = reduce_ops(8); - println!("ops: {ops:#?}"); - assert_eq!(*ops, *expected); - } - - #[test] - fn test_count_ones() { - for width in 0..=10u32 { - for v in 0..1u32 << width { - let expected = v.count_ones(); - assert_eq!( - reduce((0..width).map(|i| (v >> i) & 1), |l, r| l + r).unwrap_or(0), - expected, - "v={v:#X}" - ); - } - } - } - - #[track_caller] - fn test_diagram(ops: impl IntoIterator, item_count: usize, expected: &str) { - let text = PrefixSumOp::diagram_with_config( - ops, - item_count, - DiagramConfig { - plus: Cow::Borrowed("@"), - ..Default::default() - }, - ); - println!("text:\n{text}\n"); - assert_eq!(text, expected); - } - - #[test] - fn test_work_efficient_diagram_16() { - let item_count = 16; - test_diagram( - PrefixSumAlgorithm::WorkEfficient.ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● | ● | ● | ● | ● | ● | ● | ● | - |\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ | - | \| | \| | \| | \| | \| | \| | \| | \| - | @ | @ | @ | @ | @ | @ | @ | @ - | |\ | | | |\ | | | |\ | | | |\ | | - | | \| | | | \| | | | \| | | | \| | - | | X | | | X | | | X | | | X | - | | |\ | | | |\ | | | |\ | | | |\ | - | | | \| | | | \| | | | \| | | | \| - | | | @ | | | @ | | | @ | | | @ - | | | |\ | | | | | | | |\ | | | | - | | | | \| | | | | | | | \| | | | - | | | | X | | | | | | | X | | | - | | | | |\ | | | | | | | |\ | | | - | | | | | \| | | | | | | | \| | | - | | | | | X | | | | | | | X | | - | | | | | |\ | | | | | | | |\ | | - | | | | | | \| | | | | | | | \| | - | | | | | | X | | | | | | | X | - | | | | | | |\ | | | | | | | |\ | - | | | | | | | \| | | | | | | | \| - | | | | | | | @ | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | | | | | | | | | X | | | | - | | | | | | | | | | | |\ | | | | - | | | | | | | | | | | | \| | | | - | | | | | | | | | | | | X | | | - | | | | | | | | | | | | |\ | | | - | | | | | | | | | | | | | \| | | - | | | | | | | | | | | | | X | | - | | | | | | | | | | | | | |\ | | - | | | | | | | | | | | | | | \| | - | | | | | | | | | | | | | | X | - | | | | | | | | | | | | | | |\ | - | | | | | | | | | | | | | | | \| - | | | | | | | ● | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | ● | | | ● | | | @ | | | | - | | | |\ | | | |\ | | | |\ | | | | - | | | | \| | | | \| | | | \| | | | - | | | | X | | | X | | | X | | | - | | | | |\ | | | |\ | | | |\ | | | - | | | | | \| | | | \| | | | \| | | - | ● | ● | @ | ● | @ | ● | @ | | - | |\ | |\ | |\ | |\ | |\ | |\ | |\ | | - | | \| | \| | \| | \| | \| | \| | \| | - | | @ | @ | @ | @ | @ | @ | @ | - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_low_latency_diagram_16() { - let item_count = 16; - test_diagram( - PrefixSumAlgorithm::LowLatency.ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● | - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | \| \| \| \| \| \| \| \| \| \| \| \| \| \| \| - ● @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | - | \| \| \| \| \| \| \| \| \| \| \| \| \| \| | - | X X X X X X X X X X X X X X | - | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | | \| \| \| \| \| \| \| \| \| \| \| \| \| \| - ● ● @ @ @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | | | - | \| \| \| \| \| \| \| \| \| \| \| \| | | | - | X X X X X X X X X X X X | | | - | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | | - | | \| \| \| \| \| \| \| \| \| \| \| \| | | - | | X X X X X X X X X X X X | | - | | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | - | | | \| \| \| \| \| \| \| \| \| \| \| \| | - | | | X X X X X X X X X X X X | - | | | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | | | | \| \| \| \| \| \| \| \| \| \| \| \| - ● ● ● ● @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | | | - | \| \| \| \| \| \| \| \| | | | | | | | - | X X X X X X X X | | | | | | | - | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | | - | | \| \| \| \| \| \| \| \| | | | | | | - | | X X X X X X X X | | | | | | - | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | - | | | \| \| \| \| \| \| \| \| | | | | | - | | | X X X X X X X X | | | | | - | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | - | | | | \| \| \| \| \| \| \| \| | | | | - | | | | X X X X X X X X | | | | - | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | - | | | | | \| \| \| \| \| \| \| \| | | | - | | | | | X X X X X X X X | | | - | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | - | | | | | | \| \| \| \| \| \| \| \| | | - | | | | | | X X X X X X X X | | - | | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | - | | | | | | | \| \| \| \| \| \| \| \| | - | | | | | | | X X X X X X X X | - | | | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | - | | | | | | | | \| \| \| \| \| \| \| \| - | | | | | | | | @ @ @ @ @ @ @ @ - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_work_efficient_diagram_9() { - let item_count = 9; - test_diagram( - PrefixSumAlgorithm::WorkEfficient.ops(item_count), - item_count, - &r" - | | | | | | | | | - ● | ● | ● | ● | | - |\ | |\ | |\ | |\ | | - | \| | \| | \| | \| | - | @ | @ | @ | @ | - | |\ | | | |\ | | | - | | \| | | | \| | | - | | X | | | X | | - | | |\ | | | |\ | | - | | | \| | | | \| | - | | | @ | | | @ | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | ● | | | @ | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | ● | ● | @ | ● | - | |\ | |\ | |\ | |\ | - | | \| | \| | \| | \| - | | @ | @ | @ | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_low_latency_diagram_9() { - let item_count = 9; - test_diagram( - PrefixSumAlgorithm::LowLatency.ops(item_count), - item_count, - &r" - | | | | | | | | | - ● ● ● ● ● ● ● ● | - |\ |\ |\ |\ |\ |\ |\ |\ | - | \| \| \| \| \| \| \| \| - ● @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ | | - | \| \| \| \| \| \| \| | - | X X X X X X X | - | |\ |\ |\ |\ |\ |\ |\ | - | | \| \| \| \| \| \| \| - ● ● @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ | | | | - | \| \| \| \| \| | | | - | X X X X X | | | - | |\ |\ |\ |\ |\ | | | - | | \| \| \| \| \| | | - | | X X X X X | | - | | |\ |\ |\ |\ |\ | | - | | | \| \| \| \| \| | - | | | X X X X X | - | | | |\ |\ |\ |\ |\ | - | | | | \| \| \| \| \| - ● | | | @ @ @ @ @ - |\ | | | | | | | | - | \| | | | | | | | - | X | | | | | | | - | |\ | | | | | | | - | | \| | | | | | | - | | X | | | | | | - | | |\ | | | | | | - | | | \| | | | | | - | | | X | | | | | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - | | | | | | | | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_reduce_diagram_16() { - let item_count = 16; - test_diagram( - reduce_ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● | ● | ● | ● | ● | ● | ● | ● | - |\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ | - | \| | \| | \| | \| | \| | \| | \| | \| - | @ | @ | @ | @ | @ | @ | @ | @ - | |\ | | | |\ | | | |\ | | | |\ | | - | | \| | | | \| | | | \| | | | \| | - | | X | | | X | | | X | | | X | - | | |\ | | | |\ | | | |\ | | | |\ | - | | | \| | | | \| | | | \| | | | \| - | | | @ | | | @ | | | @ | | | @ - | | | |\ | | | | | | | |\ | | | | - | | | | \| | | | | | | | \| | | | - | | | | X | | | | | | | X | | | - | | | | |\ | | | | | | | |\ | | | - | | | | | \| | | | | | | | \| | | - | | | | | X | | | | | | | X | | - | | | | | |\ | | | | | | | |\ | | - | | | | | | \| | | | | | | | \| | - | | | | | | X | | | | | | | X | - | | | | | | |\ | | | | | | | |\ | - | | | | | | | \| | | | | | | | \| - | | | | | | | @ | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | | | | | | | | | X | | | | - | | | | | | | | | | | |\ | | | | - | | | | | | | | | | | | \| | | | - | | | | | | | | | | | | X | | | - | | | | | | | | | | | | |\ | | | - | | | | | | | | | | | | | \| | | - | | | | | | | | | | | | | X | | - | | | | | | | | | | | | | |\ | | - | | | | | | | | | | | | | | \| | - | | | | | | | | | | | | | | X | - | | | | | | | | | | | | | | |\ | - | | | | | | | | | | | | | | | \| - | | | | | | | | | | | | | | | @ - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_reduce_diagram_9() { - let item_count = 9; - test_diagram( - reduce_ops(item_count), - item_count, - &r" - | | | | | | | | | - | ● | ● | ● | ● | - | |\ | |\ | |\ | |\ | - | | \| | \| | \| | \| - | | @ | @ | @ | @ - | | |\ | | | |\ | | - | | | \| | | | \| | - | | | X | | | X | - | | | |\ | | | |\ | - | | | | \| | | | \| - | | | | @ | | | @ - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - ● | | | | | | | @ - |\ | | | | | | | | - | \| | | | | | | | - | X | | | | | | | - | |\ | | | | | | | - | | \| | | | | | | - | | X | | | | | | - | | |\ | | | | | | - | | | \| | | | | | - | | | X | | | | | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - | | | | | | | | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } -} diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index 49b226a..49f5689 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -191,14 +191,10 @@ circuit check_array_repeat: }; } -pub trait UnknownTrait {} - -impl UnknownTrait for T {} - #[hdl_module(outline_generated)] pub fn check_skipped_generics(v: U) where - T: StaticType + UnknownTrait, + T: StaticType, ConstUsize: KnownSize, U: std::fmt::Display, { @@ -380,18 +376,18 @@ circuit check_written_inside_both_if_else: }; } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct { pub a: T, pub b: UInt<8>, } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct2 { pub v: UInt<8>, } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct3 {} #[hdl_module(outline_generated)] @@ -4425,125 +4421,3 @@ circuit check_let_patterns: ", }; } - -#[hdl_module(outline_generated)] -pub fn check_struct_cmp_eq() { - #[hdl] - let tuple_lhs: (UInt<1>, SInt<1>, Bool) = m.input(); - #[hdl] - let tuple_rhs: (UInt<1>, SInt<1>, Bool) = m.input(); - #[hdl] - let tuple_cmp_eq: Bool = m.output(); - connect(tuple_cmp_eq, tuple_lhs.cmp_eq(tuple_rhs)); - #[hdl] - let tuple_cmp_ne: Bool = m.output(); - connect(tuple_cmp_ne, tuple_lhs.cmp_ne(tuple_rhs)); - - #[hdl] - let test_struct_lhs: TestStruct> = m.input(); - #[hdl] - let test_struct_rhs: TestStruct> = m.input(); - #[hdl] - let test_struct_cmp_eq: Bool = m.output(); - connect(test_struct_cmp_eq, test_struct_lhs.cmp_eq(test_struct_rhs)); - #[hdl] - let test_struct_cmp_ne: Bool = m.output(); - connect(test_struct_cmp_ne, test_struct_lhs.cmp_ne(test_struct_rhs)); - - #[hdl] - let test_struct_2_lhs: TestStruct2 = m.input(); - #[hdl] - let test_struct_2_rhs: TestStruct2 = m.input(); - #[hdl] - let test_struct_2_cmp_eq: Bool = m.output(); - connect( - test_struct_2_cmp_eq, - test_struct_2_lhs.cmp_eq(test_struct_2_rhs), - ); - #[hdl] - let test_struct_2_cmp_ne: Bool = m.output(); - connect( - test_struct_2_cmp_ne, - test_struct_2_lhs.cmp_ne(test_struct_2_rhs), - ); - - #[hdl] - let test_struct_3_lhs: TestStruct3 = m.input(); - #[hdl] - let test_struct_3_rhs: TestStruct3 = m.input(); - #[hdl] - let test_struct_3_cmp_eq: Bool = m.output(); - connect( - test_struct_3_cmp_eq, - test_struct_3_lhs.cmp_eq(test_struct_3_rhs), - ); - #[hdl] - let test_struct_3_cmp_ne: Bool = m.output(); - connect( - test_struct_3_cmp_ne, - test_struct_3_lhs.cmp_ne(test_struct_3_rhs), - ); -} - -#[test] -fn test_struct_cmp_eq() { - let _n = SourceLocation::normalize_files_for_tests(); - let m = check_struct_cmp_eq(); - dbg!(m); - #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - assert_export_firrtl! { - m => - "/test/check_struct_cmp_eq.fir": r"FIRRTL version 3.2.0 -circuit check_struct_cmp_eq: - type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>} - type Ty1 = {a: SInt<8>, b: UInt<8>} - type Ty2 = {v: UInt<8>} - type Ty3 = {} - module check_struct_cmp_eq: @[module-XXXXXXXXXX.rs 1:1] - input tuple_lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] - input tuple_rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] - output tuple_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - output tuple_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 6:1] - input test_struct_lhs: Ty1 @[module-XXXXXXXXXX.rs 8:1] - input test_struct_rhs: Ty1 @[module-XXXXXXXXXX.rs 9:1] - output test_struct_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 10:1] - output test_struct_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 12:1] - input test_struct_2_lhs: Ty2 @[module-XXXXXXXXXX.rs 14:1] - input test_struct_2_rhs: Ty2 @[module-XXXXXXXXXX.rs 15:1] - output test_struct_2_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 16:1] - output test_struct_2_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 18:1] - input test_struct_3_lhs: Ty3 @[module-XXXXXXXXXX.rs 20:1] - input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1] - output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1] - output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1] - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - wire _array_literal_expr_1: UInt<1>[3] - connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`) - wire _cast_array_to_bits_expr_1: UInt<1>[3] - connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0] - connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1] - connect _cast_array_to_bits_expr_1[2], _array_literal_expr_1[2] - wire _cast_to_bits_expr_1: UInt<3> - connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0])) - connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1] - connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1] - connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1] - connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1] - connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1] - connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1] - connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1] -", - }; -}