packages feed

clash-prelude 1.10.2 → 1.10.3

raw patch · 11 files changed

+172/−18 lines, 11 filesdep ~ghcdep ~ghc-bignumdep ~taggedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: ghc, ghc-bignum, tagged, template-haskell

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,48 @@ # Changelog for the Clash project +## 1.10.3 - *14 Oct, 2026*++### Added:+- Added support for GHC 9.14.+  [#3182](https://github.com/clash-lang/clash-compiler/pull/3182)+- Add `NumConvert` support for converting from `SNat`+  [#3455](https://github.com/clash-lang/clash-compiler/pull/3455)++### Changed:+- Normalization now knows which `Term` constructors each transformation can fire on, and only offers a node to the transformations that can match it. Measured ~25% faster HDL generation end-to-end on a large industrial design, with identical HDL. Transformations that cannot match a node no longer show up in `-fclash-debug-transformations` and `-fclash-debug-count-transformations` output.+  [#3328](https://github.com/clash-lang/clash-compiler/pull/3328)+- `Clash.Signal.Internal.resetGenN` now reports `clash-non-synthesizable` on every backend, instead of only on SystemVerilog.+  [#3410](https://github.com/clash-lang/clash-compiler/pull/3410)+- In `clash-lib`, the `reduceNonRepPrim` transformation is renamed to `reducePrim`, because it replaces primitives for more reasons than non-representable arguments or results. To debug it with `-fclash-debug-transformations`, use the new name.+  [#3462](https://github.com/clash-lang/clash-compiler/pull/3462)+- In `clash-lib`, the `inlineWorkFree` transformation now normalizes an application of a function to constant arguments only once, and reuses the result at every place the same application occurs. Before, every occurrence was normalized separately. This speeds up normalization of designs that compute a lot with type-level naturals at compile time, for example through `KnownNat` constraints.+  [#3472](https://github.com/clash-lang/clash-compiler/pull/3472)++### Fixed:+- Clash no longer errors when unused arguments of local functions are non-representable in very specific circumstances+  [#3407](https://github.com/clash-lang/clash-compiler/issues/3407)+- `ensureSpine` on a `Signal` no longer crashes Clash with an internal error. It now applies the sample's `ensureSpine` instance in HDL, preserving fixed bits in custom representations. Undefined stream recovery in simulation uses the same instance instead of `deepErrorX`, fixing mismatches for function-valued samples.+  [#3432](https://github.com/clash-lang/clash-compiler/issues/3432)+- Functions testing for `XException` (`isX`, `hasX`, `maybeIsX`, and `maybeHasX`) are now marked non-translatable. This makes the Clash compiler throw a proper error, instead of an internal one when it encounters their use.+  [#3434](https://github.com/clash-lang/clash-compiler/pull/3434)+- Clash no longer crashes when generating HDL for `toEnum` on an enumeration with a single constructor.+  [#3439](https://github.com/clash-lang/clash-compiler/issues/3439)+- Clash now reports an error when using GHC 9.12.1 through 9.12.3, which contain bugs affecting Clash. The GHC compatibility matrix now lists 9.12.4 as the minimum supported GHC 9.12 release.+  [#3415](https://github.com/clash-lang/clash-compiler/issues/3415)+- Extending arithmetic (`add`, `sub`, and `mul`) on `Index` now handles zero-width+  arguments correctly. VHDL subtraction from zero-width `BitVector`, `Signed`, and+  `Unsigned` values now negates the widened operand correctly, including boundary+  values.+  [#3310](https://github.com/clash-lang/clash-compiler/issues/3310)+- Clash now checks all input targets before loading modules or generating HDL. Invalid arguments, including Clash flags passed without their leading dash, are reported immediately, instead of after compiling earlier inputs.+  [#3314](https://github.com/clash-lang/clash-compiler/issues/3314)+- Projecting a zero-width field, such as a `CallStack`, no longer renders a reference to an undeclared `c$sel` in the HDL in very specific circumstances.+  [#3460](https://github.com/clash-lang/clash-compiler/issues/3460)+- Clash no longer takes minutes to compile designs that unroll `map`, `zipWith`, `foldr`, or `init` over vectors bound to top-level definitions. This most often happened with modules compiled with `-ffull-laziness`, which is enabled by `-O`, for example by Cabal.+  [#3461](https://github.com/clash-lang/clash-compiler/issues/3461)+- Fixed accidental free variable capture in `appProp`, which could produce subtly incorrect HDL.+  [#3478](https://github.com/clash-lang/clash-compiler/issues/3478)+ ## 1.10.2 *Sep 4th, 2026*  Highlights:@@ -60,6 +103,7 @@ * In `clash-ghc`, Clash no longer enables `-dynamic-too` when the build is already dynamic, which made GHC emit an `-Winconsistent-flags` warning. See [#3354](https://github.com/clash-lang/clash-compiler/issues/3354), fixed in [#3358](https://github.com/clash-lang/clash-compiler/pull/3358). * In `clash-lib`, the SystemVerilog backend no longer emits out-of-bounds array indices when a nested modifier selects a half of an `RTree`. The size of a tree half was computed as `(d-1)^2` instead of `2^(d-1)`, so for an `RTree 3` the right half was emitted as `[4:8]` on an array whose valid indices are `0..7`. See [#3359](https://github.com/clash-lang/clash-compiler/issues/3359), fixed in [#3360](https://github.com/clash-lang/clash-compiler/pull/3360). * In `clash-lib` and `clash-ghc`, structural equality and ordering now account for the names and types of variables, including in `eqTerm` and `eqType`, instead of relying only on variable uniques. See [#3361](https://github.com/clash-lang/clash-compiler/issues/3361), fixed in [#3362](https://github.com/clash-lang/clash-compiler/pull/3362).+* `popCount`, `countLeadingZeros` and `countTrailingZeros` on `BitVector` (and hence on `Unsigned`, `Signed` and `Index`, which delegate to it) went through `Integer`, which made Clash emit a `Dubious primitive instantiation` warning for `GHC.Num.Integer.integerToInt#` and put an `Integer` in the generated HDL. They now use `Clash.Sized.Internal.Index.fromEnum#`, which has a black box of its own. See [#3409](https://github.com/clash-lang/clash-compiler/pull/3409).  ## 1.10.1 *Aug 27th, 2026* 
clash-prelude.cabal view
@@ -1,6 +1,6 @@ Cabal-version:        2.2 Name:                 clash-prelude-Version:              1.10.2+Version:              1.10.3 Synopsis:             Clash: a functional hardware description language - Prelude library Description:   Clash is a functional hardware description language that borrows both its@@ -58,7 +58,8 @@ tested-with:          GHC == 9.6.7,                       GHC == 9.8.4,                       GHC == 9.10.3,-                      GHC == 9.12.4+                      GHC == 9.12.4,+                      GHC == 9.14.1  Extra-source-files:   README.md                       CHANGELOG.md@@ -333,7 +334,7 @@                       deepseq                   >= 1.4.1.0 && < 1.6,                       distributive              >= 0.1     && < 1.0,                       extra                     >= 1.6.17  && < 1.9,-                      ghc-bignum                >= 1.0     && < 1.4,+                      ghc-bignum                >= 1.0     && < 1.5,                       ghc-prim                  >= 0.5.1.0 && < 0.14,                       ghc-typelits-extra        >= 0.5.3   && < 0.6,                       ghc-typelits-knownnat     >= 0.8.3   && < 0.9,@@ -348,8 +349,8 @@                       checked-literals          >= 0.1.1   && < 0.2,                       singletons                >= 2.0     && < 3.1,                       string-interpolate        >= 0.3     && < 1.1,-                      tagged                    >= 0.8     && < 0.9,-                      template-haskell          >= 2.20.0.0 && < 2.24,+                      tagged                    >= 0.8     && < 0.10,+                      template-haskell          >= 2.20.0.0 && < 2.25,                       th-abstraction            >= 0.3.0 && < 0.8.0,                       th-lift                   >= 0.7.0    && < 0.9,                       th-orphans                >= 0.13.1   && < 1.0,@@ -363,7 +364,7 @@   -- Depend on GHC to obtain the maximum tuple size via   -- import GHC.Settings.Constants (mAX_TUPLE_SIZE)   if flag(large-tuples)-    Build-Depends:    ghc                       >= 9.6.0 && < 9.13+    Build-Depends:    ghc                       >= 9.6.0 && < 9.15  test-suite doctests   type:             exitcode-stdio-1.0
src/Clash/Annotations/TopEntity.hs view
@@ -184,7 +184,8 @@ Where we now have:  * A top-level component that is called @blinker@.-* Inputs and outputs that have a /user/-chosen name: @CLOCK_50@, @KEY0@, @KEY1@, @KEY2@, @LED@, etc.+* Inputs and outputs that have a /user/-chosen name: @CLOCK_50@, @KEY0@, @KEY1@,+  @KEY2@ and @LED@.  See the documentation of 'Synthesize' for the meaning of all its fields. 
src/Clash/Class/BitPack/Internal.hs view
@@ -19,6 +19,7 @@ {-# OPTIONS_GHC -fplugin=GHC.TypeLits.Extra.Solver #-} {-# OPTIONS_GHC -fplugin=GHC.TypeLits.Normalise #-} {-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}+{-# OPTIONS_GHC -fconstraint-solver-iterations=12 #-} {-# OPTIONS_HADDOCK show-extensions #-}  #include "MachDeps.h"
src/Clash/Class/NumConvert/Internal/Canonical.hs view
@@ -1,16 +1,19 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_HADDOCK hide #-}  #include "MachDeps.h"  {- | Copyright  :  (C) 2026     , Martijn Bastiaan+                  2026     , QBayLogic B.V. License    :  BSD2 (see the file LICENSE) Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> -} module Clash.Class.NumConvert.Internal.Canonical where +import Clash.Promoted.Nat (SNat) import Clash.Sized.BitVector import Clash.Sized.Index import Clash.Sized.Signed@@ -19,6 +22,8 @@ import Data.Int (Int16, Int32, Int64, Int8) import Data.Word (Word16, Word32, Word64, Word8) +import GHC.TypeLits (type (+))+ -- | Type family mapping types to their canonical \"unwrapped\" Clash form. -- This is used by 'Clash.Class.NumConvert.numConvert' and -- 'Clash.Class.NumConvert.maybeNumConvert' to determine the intermediate type.@@ -38,10 +43,11 @@ type instance Canonical Int16 = Signed 16 type instance Canonical Int8 = Signed 8 --- Bit+-- Clash types that are not in canonical form themselves type instance Canonical Bit = BitVector 1+type instance Canonical (SNat n) = Index (n + 1) --- Clash types are already in canonical form+-- Clash types that are already in canonical form type instance Canonical (Unsigned n) = Unsigned n type instance Canonical (Signed n) = Signed n type instance Canonical (BitVector n) = BitVector n
src/Clash/Class/NumConvert/Internal/NumConvert.hs view
@@ -24,6 +24,7 @@ import Clash.Class.BitPack import Clash.Class.NumConvert.Internal.Canonical import Clash.Class.Resize+import Clash.Promoted.Nat (SNat (SNat), snatToNum) import Clash.Sized.BitVector import Clash.Sized.Index import Clash.Sized.Signed@@ -226,3 +227,14 @@   numConvertCanonical = pack instance NumConvertCanonical (BitVector 1) Bit where   numConvertCanonical = unpack++{- | Concrete unidirectional instance for converting a type level 'SNat' to a+term level number.++Note: This is intentionally unidirectional: a reverse instance maintaining the+lossless round trip conversion law would require an existential (producing a+type level @n@ that is not determined by the call site) which the type of+`numConvertCanonical` cannot express.+-}+instance m ~ n + 1 => NumConvertCanonical (SNat n) (Index m) where+  numConvertCanonical sn@SNat = snatToNum sn
src/Clash/Signal/Internal.hs view
@@ -225,6 +225,7 @@  import Clash.Class.Num            (SaturatingNum(..)) import Clash.CPP                  (fStrictMapSignal)+import Clash.Magic                (clashSimulation) import Clash.NamedTypes import Clash.Promoted.Nat         (SNat (..), snatToNum, snatToNatural) import Clash.Promoted.Symbol      (SSymbol (..), ssymbolToString)@@ -877,9 +878,20 @@  instance NFDataX a => NFDataX (Signal domain a) where   deepErrorX = pure . deepErrorX-  ensureSpine s = case isX s of-    Left e -> deepErrorX e-    Right (a :- s') -> ensureSpine a :- ensureSpine s'+  -- The simulation implementation pattern matches on ':-', which Clash cannot+  -- translate to HDL: exposing the constructor crashes Clash with an internal+  -- error (#3432). Only the stream spine disappears in HDL: each sample still+  -- needs 'ensureSpine', for example to restore fixed constructor bits in a+  -- custom bit representation (#3434).+  ensureSpine s0+    | clashSimulation = go s0+    | otherwise = fmap ensureSpine s0+   where+    go s = case isX s of+      -- Recover the stream spine using the sample's own ensureSpine. Its+      -- deepErrorX need not equal ensureSpine . errorX (e.g. for functions).+      Left e -> pure (ensureSpine (errorX e))+      Right (a :- s') -> ensureSpine a :- go s'   hasUndefined = error "hasUndefined on (Signal domain a): No sensible implementation exists"   rnfX = error "rnfX on (Signal domain a): No sensible implementation exists" @@ -1982,7 +1994,7 @@ -- | The above type is a generalization for: -- -- @--- __sample__ :: 'Clash.Signal.Signal' dom a -> [a]+-- __sample_lazy__ :: 'Clash.Signal.Signal' dom a -> [a] -- @ -- -- Get an infinite list of samples from a 'Clash.Signal.Signal'@@ -1999,7 +2011,7 @@ -- | The above type is a generalization for: -- -- @--- __sampleN__ :: Int -> 'Clash.Signal.Signal' dom a -> [a]+-- __sampleN_lazy__ :: Int -> 'Clash.Signal.Signal' dom a -> [a] -- @ -- -- Get a list of @n@ samples from a 'Clash.Signal.Signal'
src/Clash/Sized/RTree.hs view
@@ -294,7 +294,27 @@ However, we cannot simply use 'Clash.Sized.Vector.fold' to create a tree-structure of 'Clash.Class.Num.add's: -#if __GLASGOW_HASKELL__ >= 910+#if __GLASGOW_HASKELL__ >= 914+>>> :{+let populationCount' :: (KnownNat (2^d), KnownNat d, KnownNat (2^d+1))+                     => BitVector (2^d) -> Index (2^d+1)+    populationCount' = tfold (resize . bv2i . pack) add . v2t . bv2v+:}+<interactive>:...+...+      Expected: Index ((2 ^ d) + 1)+        Actual: AResult (Index ((2 ^ d) + 1)) (Index ((2 ^ d) + 1))+...+    • In the second argument of ‘tfold’, namely ‘add’+      In the first argument of ‘(.)’, namely+        ‘tfold (resize . bv2i . pack) add’+      In the expression: tfold (resize . bv2i . pack) add . v2t . bv2v+    • Relevant bindings include+        populationCount' :: BitVector (2 ^ d) -> Index ((2 ^ d) + 1)+          (bound at ...)+<BLANKLINE>++#elif __GLASGOW_HASKELL__ >= 910 >>> :{ let populationCount' :: (KnownNat (2^d), KnownNat d, KnownNat (2^d+1))                      => BitVector (2^d) -> Index (2^d+1)
src/Clash/Sized/Vector.hs view
@@ -100,7 +100,11 @@ where  import Control.DeepSeq            (NFData (..))+#if __GLASGOW_HASKELL__ >= 914+import qualified Control.Lens     as Lens hiding (data (:>), data (:<))+#else import qualified Control.Lens     as Lens hiding (pattern (:>), pattern (:<))+#endif import Data.Bits                  ((.|.), shiftL) import Data.Constraint            ((:-)(Sub), Dict (..)) import Data.Constraint.Nat        (leZero)@@ -1881,8 +1885,13 @@ >>> :t xss xss :: Num a => Vec 4 (Vec 4 a) +#if __GLASGOW_HASKELL__ >= 914 >>> :t stencil2d d2 d2 (sum . map sum) xss+stencil2d d2 d2 (sum . map sum) xss :: Num b => Vec 3 (Vec 3 b)+#else+>>> :t stencil2d d2 d2 (sum . map sum) xss stencil2d d2 d2 (sum . map sum) xss :: Num a => Vec 3 (Vec 3 a)+#endif  >>> stencil2d d2 d2 (sum . map sum) xss (14 :> 18 :> 22 :> Nil) :> (30 :> 34 :> 38 :> Nil) :> (46 :> 50 :> 54 :> Nil) :> Nil@@ -2435,7 +2444,26 @@ However, we cannot simply use 'fold' to create a tree-structure of 'Clash.Class.Num.add'es: -#if __GLASGOW_HASKELL__ >= 910+#if __GLASGOW_HASKELL__ >= 914+>>> :{+let populationCount' :: (KnownNat (n+1), KnownNat (n+2))+                     => BitVector (n+1) -> Index (n+2)+    populationCount' = fold add . map fromIntegral . bv2v+:}+<interactive>:...+    • Couldn't match type: ((n + 2) + (n + 2)) - 1+                     with: n + 2+      Expected: Index (n + 2)+        Actual: AResult (Index (n + 2)) (Index (n + 2))+    • In the first argument of ‘fold’, namely ‘add’+      In the first argument of ‘(.)’, namely ‘fold add’+      In the expression: fold add . map fromIntegral . bv2v+    • Relevant bindings include+        populationCount' :: BitVector (n + 1) -> Index (n + 2)+          (bound at ...)+<BLANKLINE>++#elif __GLASGOW_HASKELL__ >= 910 >>> :{ let populationCount' :: (KnownNat (n+1), KnownNat (n+2))                      => BitVector (n+1) -> Index (n+2)
src/Clash/XException.hs view
@@ -43,7 +43,7 @@  import           Prelude             hiding (undefined) -import           Clash.Annotations.Primitive (hasBlackBox)+import           Clash.Annotations.Primitive (hasBlackBox, dontTranslate) import           Clash.CPP           (maxTupleSize, fSuperStrict) import           Clash.XException.Internal import           Clash.XException.TH@@ -297,6 +297,7 @@ -- maybeHasX :: (NFData a, NFDataX a) => a -> Maybe a maybeHasX = maybeX hasX+{-# ANN maybeHasX dontTranslate #-}  -- | Evaluate a value to WHNF, returning 'Nothing' if it throws 'XException'. --@@ -307,6 +308,7 @@ -- > maybeIsX _|_                 = _|_ maybeIsX :: a -> Maybe a maybeIsX = maybeX isX+{-# ANN maybeIsX dontTranslate #-}  -- | Fully evaluate a value, returning @'Left' msg@ if it throws 'XException'. -- If you want to determine if a value contains undefined parts, use@@ -333,6 +335,7 @@       (evaluate (rnf a) >> return (Right a))       (\(XException msg) -> evaluate (rnfX a) >> return (Left msg))) {-# OPAQUE hasX #-}+{-# ANN hasX dontTranslate #-}  -- | Evaluate a value to WHNF, returning @'Left' msg@ if is a 'XException'. --@@ -348,6 +351,7 @@       (evaluate a >> return (Right a))       (\(XException msg) -> return (Left msg))) {-# OPAQUE isX #-}+{-# ANN isX dontTranslate #-}  -- | Like the 'Show' class, but values that normally throw an 'XException' are -- converted to @undefined@, instead of error'ing out with an exception.@@ -493,7 +497,7 @@ -- -- Equivalent to @\\x -> 'seqX' x ()@. ----- Useful for defining 'NFDataX.rnfX' for types for which NF=WHNF holds.+-- Useful for defining 'rnfX' for types for which NF=WHNF holds. rwhnfX :: a -> () rwhnfX = (`seqX` ()) {-# INLINE rwhnfX #-}
tests/Clash/Tests/NFDataX.hs view
@@ -10,6 +10,7 @@  import           GHC.Generics         (Generic) import           Clash.Class.BitPack  (pack)+import           Clash.Signal.Internal (Signal(..), System) import           Clash.Sized.Vector   (Vec(..)) import           Clash.XException   (NFDataX(rnfX, hasUndefined, deepErrorX), errorX, ensureSpine)@@ -94,6 +95,30 @@         , testCase "ES1" $ case ensureSpine undef of () -> () @?= ()         , testCase "ES1" $ case ensureSpine undef of ((), ()) -> () @?= ()         , testCase "ES2" $ case ensureSpine @(Unit, Unit) undef of (Unit, Unit) -> () @?= ()+        , testCase "ES3" $+            case ensureSpine @(Signal System (Unit, Unit)) undef of+              (Unit, Unit) :- ((Unit, Unit) :- _) -> () @?= ()+        ]+    , testGroup+        "SignalEnsureSpine"+        [ testCase "Undefined function stream uses the sample instance" $ do+            -- For functions, ensureSpine = id, but deepErrorX returns a+            -- function with a structured undefined result. Stream recovery+            -- must not substitute deepErrorX for the sample's ensureSpine.+            let expected = hasUndefined (ensureSpine @(Bool -> Unit) undef False)+            case ensureSpine @(Signal System (Bool -> Unit)) undef of+              f :- (g :- _) -> do+                hasUndefined (f False) @?= expected+                hasUndefined (g False) @?= expected+        , testCase "Undefined samples in a defined stream" $+            case ensureSpine @(Signal System (Unit, Unit)) (pure undef) of+              (Unit, Unit) :- ((Unit, Unit) :- _) -> pure ()+        , testCase "Defined prefix and undefined tail" $+            case ensureSpine @(Signal System (Int, Unit)) ((42, Unit) :- undef) of+              (x, Unit) :- ((y, Unit) :- ((z, Unit) :- _)) -> do+                x @?= 42+                hasUndefined y @?= True+                hasUndefined z @?= True         ]     , testGroup         "ManualRnf"