packages feed

clash-lib 1.4.0 → 1.4.1

raw patch · 10 files changed

+326/−136 lines, 10 filesdep ~clash-preludePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: clash-prelude

API changes (from Hackage documentation)

- Clash.Rewrite.Util: mkInternalVar :: MonadUnique m => InScopeSet -> OccName -> KindOrType -> m Id
- Clash.Rewrite.Util: mkSelectorCase :: HasCallStack => (Functor m, MonadUnique m) => String -> InScopeSet -> TyConMap -> Term -> Int -> Int -> m Term
- Clash.Rewrite.Util: mkWildValBinder :: MonadUnique m => InScopeSet -> Type -> m Id
+ Clash.Core.Util: [Projections] :: (forall m. MonadUnique m => InScopeSet -> Term -> m [Term]) -> Projections
+ Clash.Core.Util: data Projections
+ Clash.Core.Util: mkInternalVar :: MonadUnique m => InScopeSet -> OccName -> KindOrType -> m Id
+ Clash.Core.Util: mkSelectorCase :: HasCallStack => MonadUnique m => String -> InScopeSet -> TyConMap -> Term -> Int -> Int -> m Term
+ Clash.Core.Util: mkWildValBinder :: MonadUnique m => InScopeSet -> Type -> m Id
- Clash.Core.Util: shouldSplit :: TyConMap -> Type -> Maybe (Term, [Type])
+ Clash.Core.Util: shouldSplit :: TyConMap -> Type -> Maybe ([Term] -> Term, Projections, [Type])
- Clash.Core.Util: shouldSplit0 :: TyConMap -> TypeView -> Maybe (Term, [Type])
+ Clash.Core.Util: shouldSplit0 :: TyConMap -> TypeView -> Maybe ([Term] -> Term, Projections, [Type])
- Clash.Rewrite.Types: bindings :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) BindingMap
+ Clash.Rewrite.Types: bindings :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) BindingMap
- Clash.Rewrite.Types: curFun :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) (Id, SrcSpan)
+ Clash.Rewrite.Types: curFun :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) (Id, SrcSpan)
- Clash.Rewrite.Types: extra :: forall extra_a3s8j extra_a3sgJ. Lens (RewriteState extra_a3s8j) (RewriteState extra_a3sgJ) extra_a3s8j extra_a3sgJ
+ Clash.Rewrite.Types: extra :: forall extra_a3uko extra_a3usO. Lens (RewriteState extra_a3uko) (RewriteState extra_a3usO) extra_a3uko extra_a3usO
- Clash.Rewrite.Types: globalHeap :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) PrimHeap
+ Clash.Rewrite.Types: globalHeap :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) PrimHeap
- Clash.Rewrite.Types: nameCounter :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) Int
+ Clash.Rewrite.Types: nameCounter :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) Int
- Clash.Rewrite.Types: transformCounter :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) Int
+ Clash.Rewrite.Types: transformCounter :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) Int
- Clash.Rewrite.Types: uniqSupply :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) Supply
+ Clash.Rewrite.Types: uniqSupply :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) Supply
- Clash.Rewrite.Types: workFreeBinders :: forall extra_a3s8j. Lens' (RewriteState extra_a3s8j) (VarEnv Bool)
+ Clash.Rewrite.Types: workFreeBinders :: forall extra_a3uko. Lens' (RewriteState extra_a3uko) (VarEnv Bool)

Files

CHANGELOG.md view
@@ -1,5 +1,21 @@ # Changelog for the Clash project-## 1.4.0 *March 12th 2020*++## 1.4.1 *April 6th 2021*+Fixed:++ * Broken VHDL primitive template for setSlice# [#1715](https://github.com/clash-lang/clash-compiler/issues/1715)+ * Unable to reduce nested type families [#1721](https://github.com/clash-lang/clash-compiler/issues/1721)+ * DEC transformation fails for functions applied to more than 62 arguments [#1669](https://github.com/clash-lang/clash-compiler/issues/1669)+ * Erroneous examples in BlockRam.File and ROM.File documentation [#1608](https://github.com/clash-lang/clash-compiler/issues/1608)+ * Blackboxes of `Clash.Sized.Vector` functions error on vectors containing `Clocks`, `Reset`, or `Enable` [#1606](https://github.com/clash-lang/clash-compiler/issues/1606)+ * `Clash.Signal.Delayed.delayI` cannot be reset, the `HiddenReset` constraint was unintentional. Asserting its reset has never worked. Removed the constraint [#1739](https://github.com/clash-lang/clash-compiler/pull/1739).+ * Annotate attributes cannot use type families [#1742](https://github.com/clash-lang/clash-compiler/issues/1742)++Changed:++ * `Clash.Prelude.ROM.File.romFile` now takes an `Enum addr => addr` as address argument, making it actually useful. [#407](https://github.com/clash-lang/clash-compiler/issues/407)++## 1.4.0 *March 12th 2021* Highlighted changes (repeated in other categories):    * Clash no longer disables the monomorphism restriction. See [#1270](https://github.com/clash-lang/clash-compiler/issues/1270), and mentioned issues, as to why. This can cause, among other things, certain eta-reduced descriptions of sequential circuits to no longer type-check. See [#1349](https://github.com/clash-lang/clash-compiler/pull/1349) for code hints on what kind of changes to make to your own code in case it no longer type-checks due to this change.
clash-lib.cabal view
@@ -1,6 +1,6 @@ Cabal-version:        2.2 Name:                 clash-lib-Version:              1.4.0+Version:              1.4.1 Synopsis:             Clash: a functional hardware description language - As a library Description:   Clash is a functional hardware description language that borrows both its@@ -139,12 +139,12 @@                       aeson-pretty            >= 0.8      && < 0.9,                       ansi-terminal           >= 0.8.0.0  && < 0.12,                       array,-                      attoparsec              >= 0.10.4.0 && < 0.14,+                      attoparsec              >= 0.10.4.0 && < 0.15,                       base                    >= 4.11     && < 5,                       base16-bytestring       >= 0.1.1    && < 1.1,                       binary                  >= 0.8.5    && < 0.11,                       bytestring              >= 0.10.0.2 && < 0.12,-                      clash-prelude           == 1.4.0,+                      clash-prelude           == 1.4.1,                       concurrent-supply       >= 0.1.7    && < 0.2,                       containers              >= 0.5.0.0  && < 0.7,                       cryptohash-sha256       >= 0.11     && < 0.12,
prims/vhdl/Clash_Sized_Internal_BitVector.primitives view
@@ -309,11 +309,11 @@            -> BitVector (m + 1 + i)"     , "template" : "-- setSlice begin-~GENSYM[setSlice][0] : process(~VAR[bv][0]~VARS[4])-  variable ~GENSYM[ivec][1] : ~TYP[0];+~GENSYM[setSlice][0] : process(~VAR[bv][1]~VARS[4])+  variable ~GENSYM[ivec][1] : ~TYP[1]; begin-  ~SYM[1] := ~ARG[1];-  ~SYM[1](~LIT[2] downto ~LIT[3]) := ~VAR[bv][4];+  ~SYM[1] := ~VAR[bv][1];+  ~SYM[1](~LIT[2] downto ~LIT[3]) := ~ARG[4];   ~RESULT <= ~SYM[1]; end process; -- setSlice end"
src/Clash/Core/Type.hs view
@@ -490,7 +490,10 @@     -- to different types, so this is OK for our purposes.     go (AppTy a1 r1) (AppTy a2 r2) = do       s1 <- funSubst tcm (Just s) (a1, a2)-      funSubst tcm (Just s1) (r1, r2)+      funSubst tcm (Just s1)+                   ( r1+                   , argView tcm r2 -- See [Note: Eager type families]+                   )      go ty1@(ConstTy _) ty2 =       -- Looks through AnnType
src/Clash/Core/Util.hs view
@@ -7,16 +7,18 @@ -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE TemplateHaskell #-}  module Clash.Core.Util where  import           Control.Concurrent.Supply     (Supply, freshId) import qualified Control.Lens                  as Lens-import Control.Monad.Trans.Except              (Except, throwE)+import Control.Monad.Trans.Except              (Except, throwE, runExcept) import qualified Data.HashSet                  as HashSet import qualified Data.Graph                    as Graph import Data.List                               (foldl', mapAccumR)@@ -46,6 +48,7 @@ import Clash.Core.Pretty                 (showPpr) import Clash.Core.Subst import Clash.Core.Term+import Clash.Core.TermInfo               (termType) import Clash.Core.TyCon                  (TyConMap, tyConDataCons) import Clash.Core.Type import Clash.Core.TysPrim                (typeNatKind)@@ -458,24 +461,37 @@ tyLitShow _ (LitTy (NumTy s))        = return (show s) tyLitShow _ ty = throwE $ $(curLoc) ++ "Cannot reduce to a string:\n" ++ showPpr ty +-- | Helper existential for 'shouldSplit', contains a function that:+--+-- 1. given a term of a type that should be split,+-- 2. creates projections of that term for all the constructor arguments+data Projections where+  Projections :: (forall m . MonadUnique m => InScopeSet -> Term -> m [Term])+              -> Projections+ -- | Determine whether we should split away types from a product type, i.e. -- clocks should always be separate arguments, and not part of a product. shouldSplit   :: TyConMap   -> Type   -- ^ Type to examine-  -> Maybe (Term,[Type])+  -> Maybe ([Term] -> Term, Projections, [Type])   -- ^ If we want to split values of the given type then we have /Just/:   --   -- 1. The (type-applied) data-constructor which, when applied to values of-  --    the types in 2., creates a value of the examined type+  --    the types in 3., creates a value of the examined type   ---  -- 2. The arguments types of the product we are trying to split.+  -- 2. Function that give a term of the type we need to split, creates projections+  --    of that term for all the types in 3.   --+  -- 3. The arguments types of the product we are trying to split.+  --   -- Note that we only split one level at a time (although we check all the way   -- down), e.g. given /(Int, (Clock, Bool))/ we return:   ---  -- > Just ((,) @Int @(Clock, Bool), [Int, (Clock, Bool)])+  -- > Just ( (,) @Int @(Clock, Bool)+  -- >      , \s -> [case s of (a,b) -> a, case s of (a,b) -> b]+  -- >      , [Int, (Clock, Bool)])   --   -- An outer loop is required to subsequently split the /(Clock, Bool)/ tuple. shouldSplit tcm (tyView ->  TyConApp (nameOcc -> "Clash.Explicit.SimIO.SimIO") [tyArg]) =@@ -487,17 +503,51 @@ shouldSplit0   :: TyConMap   -> TypeView-  -> Maybe (Term,[Type])+  -> Maybe ([Term] -> Term, Projections, [Type]) shouldSplit0 tcm (TyConApp tcNm tyArgs)   | Just tc <- lookupUniqMap tcNm tcm   , [dc] <- tyConDataCons tc-  , let dcArgs  = substArgTys dc tyArgs+  , let dcArgs = substArgTys dc tyArgs+  , let dcArgsLen = length dcArgs+  , dcArgsLen > 1   , let dcArgVs = map (tyView . coreView tcm) dcArgs   = if any shouldSplitTy dcArgVs && not (isHidden tcNm tyArgs) then-      Just (mkApps (Data dc) (map Right tyArgs), dcArgs)+      Just ( mkApps (Data dc) . (map Right tyArgs ++) . map Left+           , Projections+             (\is0 subj -> mapM (mkSelectorCase ($(curLoc) ++ "splitArg") is0 tcm subj 1)+                                [0..dcArgsLen - 1])+           , dcArgs+           )     else       Nothing+  | "Clash.Sized.Vector.Vec" <- nameOcc tcNm+  , [nTy,argTy] <- tyArgs+  , Right n <- runExcept (tyNatSize tcm nTy)+  , n > 1+  , Just tc <- lookupUniqMap tcNm tcm+  , [nil,cons] <- tyConDataCons tc+  = if shouldSplitTy (tyView (coreView tcm argTy)) then+      Just ( mkVec nil cons argTy n+           , Projections (\is0 subj -> mapM (mkVecSelector is0 subj) [0..n-1])+           , replicate (fromInteger n) argTy)+    else+      Nothing  where+  -- Project the n'th value out of a vector+  --+  -- >>> mkVecSelector subj 0+  -- case subj of Cons x xs -> x+  --+  -- >>> mkVecSelector subj 2+  -- case (case (case subj of Cons x xs -> xs) of Cons x xs -> xs) of Cons x xs -> x+  mkVecSelector :: forall m . MonadUnique m => InScopeSet -> Term -> Integer -> m Term+  mkVecSelector is0 subj 0 =+    mkSelectorCase ($(curLoc) ++ "mkVecSelector") is0 tcm subj 2 1++  mkVecSelector is0 subj !n = do+    subj1 <- mkSelectorCase ($(curLoc) ++ "mkVecSelector") is0 tcm subj 2 2+    mkVecSelector is0 subj1 (n-1)+   shouldSplitTy :: TypeView -> Bool   shouldSplitTy ty = isJust (shouldSplit0 tcm ty) || splitTy ty @@ -554,8 +604,8 @@ splitShouldSplit tcm = foldr go []  where   go ty rest = case shouldSplit tcm ty of-    Just (_,tys) -> splitShouldSplit tcm tys ++ rest-    Nothing      -> ty : rest+    Just (_,_,tys) -> splitShouldSplit tcm tys ++ rest+    Nothing        -> ty : rest  -- | Strip implicit parameter wrappers (IP) stripIP :: Type -> Type@@ -601,3 +651,59 @@                             (Set.elems (Lens.setOf freeLocalIds e) )                   in  ((i,e),varUniq i,fvs))) {-# SCC sccLetBindings #-}++-- | Make a case-decomposition that extracts a field out of a (Sum-of-)Product type+mkSelectorCase+  :: HasCallStack+  => MonadUnique m+  => String -- ^ Name of the caller of this function+  -> InScopeSet+  -> TyConMap -- ^ TyCon cache+  -> Term -- ^ Subject of the case-composition+  -> Int -- ^ n'th DataCon+  -> Int -- ^ n'th field+  -> m Term+mkSelectorCase caller inScope tcm scrut dcI fieldI = go (termType tcm scrut)+  where+    go (coreView1 tcm -> Just ty') = go ty'+    go scrutTy@(tyView -> TyConApp tc args) =+      case tyConDataCons (lookupUniqMap' tcm tc) of+        [] -> cantCreate $(curLoc) ("TyCon has no DataCons: " ++ show tc ++ " " ++ showPpr tc) scrutTy+        dcs | dcI > length dcs -> cantCreate $(curLoc) "DC index exceeds max" scrutTy+            | otherwise -> do+          let dc = indexNote ($(curLoc) ++ "No DC with tag: " ++ show (dcI-1)) dcs (dcI-1)+          let (Just fieldTys) = dataConInstArgTysE inScope tcm dc args+          if fieldI >= length fieldTys+            then cantCreate $(curLoc) "Field index exceed max" scrutTy+            else do+              wildBndrs <- mapM (mkWildValBinder inScope) fieldTys+              let ty = indexNote ($(curLoc) ++ "No DC field#: " ++ show fieldI) fieldTys fieldI+              selBndr <- mkInternalVar inScope "sel" ty+              let bndrs  = take fieldI wildBndrs ++ [selBndr] ++ drop (fieldI+1) wildBndrs+                  pat    = DataPat dc (dcExtTyVars dc) bndrs+                  retVal = Case scrut ty [ (pat, Var selBndr) ]+              return retVal+    go scrutTy = cantCreate $(curLoc) ("Type of subject is not a datatype: " ++ showPpr scrutTy) scrutTy++    cantCreate loc info scrutTy = error $ loc ++ "Can't create selector " ++ show (caller,dcI,fieldI) ++ " for: (" ++ showPpr scrut ++ " :: " ++ showPpr scrutTy ++ ")\nAdditional info: " ++ info++-- | Make a binder that should not be referenced+mkWildValBinder+  :: (MonadUnique m)+  => InScopeSet+  -> Type+  -> m Id+mkWildValBinder is = mkInternalVar is "wild"++-- | Make a new, unique, identifier+mkInternalVar+  :: (MonadUnique m)+  => InScopeSet+  -> OccName+  -- ^ Name of the identifier+  -> KindOrType+  -> m Id+mkInternalVar inScope name ty = do+  i <- getUniqueM+  let nm = mkUnsafeInternalName name i+  return (uniqAway inScope (mkLocalId ty nm))
src/Clash/Driver.hs view
@@ -168,7 +168,7 @@      = PortName "" : go res (p:ps)    | otherwise =     case shouldSplit tcm a of-      Just (_,argTys@(_:_:_)) ->+      Just (_,_,argTys@(_:_:_)) ->         -- Port must be split up into 'n' pieces.. can it?         case p of           PortProduct nm portNames0 ->
src/Clash/Normalize/DEC.hs view
@@ -55,12 +55,24 @@ import qualified Data.Maybe                       as Maybe import           Data.Monoid                      (All (..)) +#if MIN_VERSION_ghc(8,10,0)+import           GHC.Hs.Utils                     (chunkify,mkChunkified)+#else+import           HsUtils                          (chunkify,mkChunkified)+#endif++#if MIN_VERSION_ghc(9,0,0)+import           GHC.Settings.Constants           (mAX_TUPLE_SIZE)+#else+import           Constants                        (mAX_TUPLE_SIZE)+#endif+ #if EXPERIMENTAL_EVALUATOR import           System.IO.Unsafe #endif  -- internal-import Clash.Core.DataCon    (DataCon, dcTag)+import Clash.Core.DataCon    (DataCon)  #if EXPERIMENTAL_EVALUATOR import Clash.Core.PartialEval@@ -75,16 +87,15 @@   (LetBinding, Pat (..), PrimInfo (..), Term (..), TickInfo (..), collectArgs,    collectArgsTicks, mkApps, mkTicks, patIds) import Clash.Core.TermInfo   (termType)-import Clash.Core.TyCon      (tyConDataCons)+import Clash.Core.TyCon      (TyConMap, TyConName, tyConDataCons) import Clash.Core.Type       (Type, isPolyFunTy, mkTyConApp, splitFunForallTy)-import Clash.Core.Util       (sccLetBindings)-import Clash.Core.Var        (isGlobalId)+import Clash.Core.Util       (mkInternalVar, mkSelectorCase, sccLetBindings)+import Clash.Core.Var        (isGlobalId, isLocalId) import Clash.Core.VarEnv   (InScopeSet, elemInScopeSet, extendInScopeSetList, notElemInScopeSet, unionInScope) import Clash.Normalize.Types (NormalizeState) import Clash.Rewrite.Types-import Clash.Rewrite.Util    (mkInternalVar, mkSelectorCase,-                              isUntranslatableType)+import Clash.Rewrite.Util    (isUntranslatableType) import Clash.Rewrite.WorkFree (isConstant) import Clash.Unique          (lookupUniqMap) import Clash.Util@@ -389,29 +400,25 @@   -> RewriteMonad NormalizeState (Maybe LetBinding,[Term]) disJointSelProj _ _ (Leaf []) = return (Nothing,[]) disJointSelProj inScope argTys cs = do+    tcm    <- Lens.view tcCache+    tupTcm <- Lens.view tupleTcCache     let maxIndex = length argTys - 1         css = map (\i -> fmap ((:[]) . (!!i)) cs) [0..maxIndex]     (untran,tran) <- List.partitionM (isUntranslatableType False . snd) (zip [0..] argTys)     let untranCs   = map (css!!) (map fst untran)-        untranSels = zipWith (\(_,ty) cs' -> genCase ty Nothing []  cs')+        untranSels = zipWith (\(_,ty) cs' -> genCase tcm tupTcm ty [ty]  cs')                              untran untranCs     (lbM,projs) <- case tran of       []       -> return (Nothing,[])-      [(i,ty)] -> return (Nothing,[genCase ty Nothing [] (css!!i)])+      [(i,ty)] -> return (Nothing,[genCase tcm tupTcm ty [ty] (css!!i)])       tys      -> do-        tcm    <- Lens.view tcCache-        tupTcm <- Lens.view tupleTcCache         let m            = length tys-            Just tupTcNm = IM.lookup m tupTcm-            Just tupTc   = lookupUniqMap tupTcNm tcm-            [tupDc]      = tyConDataCons tupTc             (tyIxs,tys') = unzip tys-            tupTy        = mkTyConApp tupTcNm tys'+            tupTy        = mkBigTupTy tcm tupTcm tys'             cs'          = fmap (\es -> map (es !!) tyIxs) cs-            djCase       = genCase tupTy (Just tupDc) tys' cs'+            djCase       = genCase tcm tupTcm tupTy tys' cs'         scrutId <- mkInternalVar inScope "tupIn" tupTy-        projections <- mapM (mkSelectorCase ($(curLoc) ++ "disJointSelProj")-                                            inScope tcm (Var scrutId) (dcTag tupDc)) [0..m-1]+        projections <- mapM (mkBigTupSelector inScope tcm tupTcm (Var scrutId) tys') [0..m-1]         return (Just (scrutId,djCase),projections)     let selProjs = tranOrUnTran 0 (zip (map fst untran) untranSels) projs @@ -437,7 +444,7 @@     Left tm  -> getAll (Lens.foldMapOf (termFreeVars' isLocallyBound)                                        (const (All False)) tm) -  isLocallyBound v = v `notElemInScopeSet` inScope+  isLocallyBound v = isLocalId v && v `notElemInScopeSet` inScope  -- | Create a list of arguments given a map of positions to common arguments, -- and a list of arguments@@ -453,17 +460,16 @@  -- | Create a case-expression that selects between the distinct arguments given -- a case-tree-genCase :: Type -- ^ Type of the alternatives-        -> Maybe DataCon -- ^ DataCon to pack multiple arguments+genCase :: TyConMap+        -> IM.IntMap TyConName+        -> Type -- ^ Type of the alternatives         -> [Type] -- ^ Types of the arguments         -> CaseTree [Term] -- ^ CaseTree of arguments         -> Term-genCase ty dcM argTys = go+genCase tcm tupTcm ty argTys = go   where     go (Leaf tms) =-      case dcM of-        Just dc -> mkApps (Data dc) (map Right argTys ++ map Left tms)-        _ -> head tms+      mkBigTupTm tcm tupTcm (List.zipEqual argTys tms)      go (LB lb ct) =       Letrec lb (go ct)@@ -477,6 +483,67 @@      go (Branch scrut pats) =       Case scrut ty (map (second go) pats)++-- | Lookup the TyConName and DataCon for a tuple of size n+findTup :: TyConMap -> IM.IntMap TyConName -> Int -> (TyConName,DataCon)+findTup tcm tupTcm n = (tupTcNm,tupDc)+  where+    tupTcNm      = Maybe.fromMaybe (error $ $curLoc ++ "Can't find " ++ show n ++ "-tuple") $ IM.lookup n tupTcm+    Just tupTc   = lookupUniqMap tupTcNm tcm+    [tupDc]      = tyConDataCons tupTc++mkBigTupTm :: TyConMap -> IM.IntMap TyConName -> [(Type,Term)] -> Term+mkBigTupTm tcm tupTcm args = snd $ mkBigTup tcm tupTcm args++mkSmallTup,mkBigTup :: TyConMap -> IM.IntMap TyConName -> [(Type,Term)] -> (Type,Term)+mkSmallTup _ _ [] = error $ $curLoc ++ "mkSmallTup: Can't create 0-tuple"+mkSmallTup _ _ [(ty,tm)] = (ty,tm)+mkSmallTup tcm tupTcm args = (ty,tm)+  where+    (argTys,tms) = unzip args+    (tupTcNm,tupDc) = findTup tcm tupTcm (length args)+    tm = mkApps (Data tupDc) (map Right argTys ++ map Left tms)+    ty = mkTyConApp tupTcNm argTys++mkBigTup tcm tupTcm = mkChunkified (mkSmallTup tcm tupTcm)++mkSmallTupTy,mkBigTupTy+  :: TyConMap+  -> IM.IntMap TyConName+  -> [Type]+  -> Type+mkSmallTupTy _ _ [] = error $ $curLoc ++ "mkSmallTupTy: Can't create 0-tuple"+mkSmallTupTy _ _ [ty] = ty+mkSmallTupTy tcm tupTcm tys = mkTyConApp tupTcNm tys+  where+    m = length tys+    (tupTcNm,_) = findTup tcm tupTcm m++mkBigTupTy tcm tupTcm = mkChunkified (mkSmallTupTy tcm tupTcm)++mkSmallTupSelector,mkBigTupSelector+  :: MonadUnique m+  => InScopeSet+  -> TyConMap+  -> IM.IntMap TyConName+  -> Term+  -> [Type]+  -> Int+  -> m Term+mkSmallTupSelector _ _ _ scrut [_] 0 = return scrut+mkSmallTupSelector _ _ _ _     [_] n = error $ $curLoc ++ "mkSmallTupSelector called with one type, but to select " ++ show n+mkSmallTupSelector inScope tcm _ scrut _ n = mkSelectorCase ($curLoc ++ "mkSmallTupSelector") inScope tcm scrut 1 n++mkBigTupSelector inScope tcm tupTcm scrut tys n = go (chunkify tys)+  where+    go [_] = mkSmallTupSelector inScope tcm tupTcm scrut tys n+    go tyss = do+      let (nOuter,nInner) = divMod n mAX_TUPLE_SIZE+          tyss' = map (mkSmallTupTy tcm tupTcm) tyss+      outer <- mkSmallTupSelector inScope tcm tupTcm scrut tyss' nOuter+      inner <- mkSmallTupSelector inScope tcm tupTcm outer (tyss List.!! nOuter) nInner+      return inner+  -- | Determine if a term in a function position is interesting to lift out of -- of a case-expression.
src/Clash/Normalize/Strategy.hs view
@@ -60,7 +60,7 @@                                       ,("letFlat"        , flattenLet)])                  >-> rmDeadcode >-> letTL     splitArgs  = topdownR (apply "separateArguments" separateArguments) !->-                 topdownR (apply "caseCon" caseCon)+                 bottomupR (apply "caseCon" caseCon)     bindSimIO  = topdownR (apply "bindSimIO" inlineSimIO)  
src/Clash/Normalize/Transformations.hs view
@@ -117,11 +117,11 @@                                               normalizeType, splitFunForallTy,                                               splitFunTy,                                               tyView, mkPolyFunTy, coreView,-                                              LitTy (..), coreView1)+                                              LitTy (..), coreView1, mkTyConApp) import           Clash.Core.TyCon            (TyConMap, tyConDataCons) import           Clash.Core.Util-  ( isSignalType, mkVec, tyNatSize, undefinedTm,-   shouldSplit, inverseTopSortLetBindings)+  (Projections (..), isSignalType, mkVec, tyNatSize, undefinedTm,+   shouldSplit, inverseTopSortLetBindings, mkInternalVar, mkSelectorCase) import           Clash.Core.Var   (Id, TyVar, Var (..), isGlobalId, isLocalId, mkLocalId) import           Clash.Core.VarEnv@@ -2142,6 +2142,26 @@ -- * Clash.Sized.RTree.treplicate -- * Clash.Sized.Internal.BitVector.split# -- * Clash.Sized.Internal.BitVector.eq#+--+-- Note [Unroll shouldSplit types]+-- 1. Certain higher-order functions over Vec, such as map, have specialized+-- code-paths to turn them into generate-for loops in HDL, instead of having to+-- having to unroll/inline their recursive definitions, e.g. Clash.Sized.Vector.map+--+-- 2. Clash, in general, translates Haskell product types to VHDL records. This+-- mostly works out fine, there is however one exception: certain synthesis+-- tools, and some HDL simulation tools (like verilator), do not like it when+-- the clock (and certain other global control signals) is contained in a+-- record type; they want them to be separate inputs to the entity/module.+-- And Clash actually does some transformations to try to ensure that values of+-- type Clock do not end up in a VHDL record type.+--+-- The problem is that the transformations in 2. never took into account the+-- specialized code-paths in 1. Making the code-paths in 1. aware of the+-- transformations in 2. is really not worth the effort for such a niche case.+-- It's easier to just unroll the recursive definitions.+--+-- See https://github.com/clash-lang/clash-compiler/issues/1606 reduceNonRepPrim :: HasCallStack => NormRewrite reduceNonRepPrim c@(TransformContext is0 ctx) e@(App _ _) | (Prim p, args, ticks) <- collectArgsTicks e = do   tcm <- Lens.view tcCache@@ -2157,12 +2177,18 @@     tv -> let argLen = length args in case primName p of       "Clash.Sized.Vector.zipWith" | argLen == 7 -> do         let [lhsElTy,rhsElty,resElTy,nTy] = Either.rights args+            TyConApp vecTcNm _ = tv+            lhsTy = mkTyConApp vecTcNm [nTy,lhsElTy]+            rhsTy = mkTyConApp vecTcNm [nTy,rhsElty]         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx                                  , List.anyM isUntranslatableType_not_poly-                                        [lhsElTy,rhsElty,resElTy] ]+                                        [lhsElTy,rhsElty,resElTy]+                                 -- Note [Unroll shouldSplit types]+                                 , pure (any (Maybe.isJust . shouldSplit tcm)+                                             [lhsTy,rhsTy,eTy]) ]             if shouldReduce1                then let [fun,lhsArg,rhsArg] = Either.lefts args                     in  (`mkTicks` ticks) <$>@@ -2171,12 +2197,17 @@           _ -> return e       "Clash.Sized.Vector.map" | argLen == 5 -> do         let [argElTy,resElTy,nTy] = Either.rights args+            TyConApp vecTcNm _ = tv+            argTy = mkTyConApp vecTcNm [nTy,argElTy]         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2 )                                  , shouldReduce ctx                                  , List.anyM isUntranslatableType_not_poly-                                        [argElTy,resElTy] ]+                                        [argElTy,resElTy]+                                 -- Note [Unroll shouldSplit types]+                                 , pure (any (Maybe.isJust . shouldSplit tcm)+                                             [argTy,eTy]) ]             if shouldReduce1                then let [fun,arg] = Either.lefts args                     in  (`mkTicks` ticks) <$> reduceMap c p n argElTy resElTy fun arg@@ -2190,27 +2221,31 @@             in  (`mkTicks` ticks) <$> reduceTraverse c n aTy fTy bTy dict fun arg           _ -> return e       "Clash.Sized.Vector.fold" | argLen == 4 -> do-        let [nTy,aTy] = Either.rights args+        let ([fun,arg],[nTy,aTy]) = Either.partitionEithers args+            argTy = termType tcm arg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n == 0)                                  , shouldReduce ctx-                                 , isUntranslatableType_not_poly aTy ]+                                 , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy))]             if shouldReduce1 then-              let [fun,arg] = Either.lefts args-              in  (`mkTicks` ticks) <$> reduceFold c (n + 1) aTy fun arg+              (`mkTicks` ticks) <$> reduceFold c (n + 1) aTy fun arg             else return e           _ -> return e       "Clash.Sized.Vector.foldr" | argLen == 6 ->-        let [aTy,bTy,nTy] = Either.rights args+        let ([fun,start,arg],[aTy,bTy,nTy]) = Either.partitionEithers args+            argTy = termType tcm arg         in  case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx-                                 , List.anyM isUntranslatableType_not_poly [aTy,bTy] ]+                                 , List.anyM isUntranslatableType_not_poly [aTy,bTy]+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-              then let [fun,start,arg] = Either.lefts args-                   in  (`mkTicks` ticks) <$> reduceFoldr c p n aTy fun start arg+              then (`mkTicks` ticks) <$> reduceFoldr c p n aTy fun start arg               else return e           _ -> return e       "Clash.Sized.Vector.dfold" | argLen == 8 ->@@ -2227,7 +2262,9 @@                 | m == 0 -> changed lArg                 | otherwise -> do                     shouldReduce1 <- List.orM [ shouldReduce ctx-                                         , isUntranslatableType_not_poly aTy ]+                                         , isUntranslatableType_not_poly aTy+                                         -- Note [Unroll shouldSplit types]+                                         , pure (Maybe.isJust (shouldSplit tcm eTy)) ]                     if shouldReduce1                        then (`mkTicks` ticks) <$> reduceAppend is0 n m aTy lArg rArg                        else return e@@ -2235,10 +2272,13 @@       "Clash.Sized.Vector.head" | argLen == 3 -> do         let [nTy,aTy] = Either.rights args             [vArg]    = Either.lefts args+            argTy     = termType tcm vArg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx-                                 , isUntranslatableType_not_poly aTy ]+                                 , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceHead is0 (n+1) aTy vArg                else return e@@ -2246,10 +2286,13 @@       "Clash.Sized.Vector.tail" | argLen == 3 -> do         let [nTy,aTy] = Either.rights args             [vArg]    = Either.lefts args+            argTy     = termType tcm vArg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx-                                 , isUntranslatableType_not_poly aTy ]+                                 , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceTail is0 (n+1) aTy vArg                else return e@@ -2257,10 +2300,13 @@       "Clash.Sized.Vector.last" | argLen == 3 -> do         let [nTy,aTy] = Either.rights args             [vArg]    = Either.lefts args+            argTy     = termType tcm vArg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy))                                  ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceLast is0 (n+1) aTy vArg@@ -2269,10 +2315,13 @@       "Clash.Sized.Vector.init" | argLen == 3 -> do         let [nTy,aTy] = Either.rights args             [vArg]    = Either.lefts args+            argTy     = termType tcm vArg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx-                                 , isUntranslatableType_not_poly aTy ]+                                 , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceInit is0 p n aTy vArg                else return e@@ -2293,6 +2342,8 @@           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm eTy))                                  ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceReplicate n aTy eTy vArg@@ -2306,6 +2357,8 @@             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx                                  , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm eTy))                                  ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceReplace_int is0 n aTy eTy vArg iArg aArg@@ -2314,11 +2367,14 @@        "Clash.Sized.Vector.index_int" | argLen == 5 -> do         let ([_knArg,vArg,iArg],[nTy,aTy]) = Either.partitionEithers args+            argTy = termType tcm vArg         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx-                                 , isUntranslatableType_not_poly aTy ]+                                 , isUntranslatableType_not_poly aTy+                                 -- Note [Unroll shouldSplit types]+                                 , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceIndex_int is0 n aTy vArg iArg                else return e@@ -2326,11 +2382,16 @@        "Clash.Sized.Vector.imap" | argLen == 6 -> do         let [nTy,argElTy,resElTy] = Either.rights args+            TyConApp vecTcNm _ = tv+            argTy = mkTyConApp vecTcNm [nTy,argElTy]         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx-                                 , List.anyM isUntranslatableType_not_poly [argElTy,resElTy] ]+                                 , List.anyM isUntranslatableType_not_poly [argElTy,resElTy]+                                 -- Note [Unroll shouldSplit types]+                                 , pure (any (Maybe.isJust . shouldSplit tcm)+                                             [argTy,eTy]) ]             if shouldReduce1                then let [_,fun,arg] = Either.lefts args                     in  (`mkTicks` ticks) <$> reduceImap c n argElTy resElTy fun arg@@ -2343,7 +2404,9 @@             shouldReduce1 <- List.orM               [ pure (ultra || n < 2)               , shouldReduce ctx-              , isUntranslatableType_not_poly aTy ]+              , isUntranslatableType_not_poly aTy+              -- Note [Unroll shouldSplit types]+              , pure (Maybe.isJust (shouldSplit tcm eTy)) ]              if shouldReduce1 then               (`mkTicks` ticks) <$> reduceIterateI c n aTy eTy f a@@ -2888,12 +2951,12 @@   -- ^ If lambda is split up, this function returns a Just containing the new term separateLambda tcm ctx@(TransformContext is0 _) b eb0 =   case shouldSplit tcm (varType b) of-    Just (dc,argTys@(_:_:_)) ->+    Just (dc, _, argTys) ->       let         nm = mkDerivedName ctx (nameOcc (varName b))         bs0 = map (`mkLocalId` nm) argTys         (is1, bs1) = List.mapAccumL newBinder is0 bs0-        subst = extendIdSubst (mkSubst is1) b (mkApps dc (map (Left . Var) bs1))+        subst = extendIdSubst (mkSubst is1) b (dc (map Var bs1))         eb1 = substTm "separateArguments" subst eb0       in         Just (mkLams eb1 bs1)@@ -2953,9 +3016,8 @@     tcm <- Lens.view tcCache     let argTy = termType tcm tmArg     case shouldSplit tcm argTy of-      Just (_,argTys@(_:_:_)) -> do-        tmArgs <- mapM (mkSelectorCase ($(curLoc) ++ "splitArg") is0 tcm tmArg 1)-                       [0..length argTys - 1]+      Just (_,Projections projections,_) -> do+        tmArgs <- projections is0 tmArg         changed (map ((ty,) . Left) tmArgs)       _ ->         return [(ty,arg)]
src/Clash/Rewrite/Util.hs view
@@ -65,8 +65,6 @@ import           BasicTypes                  (InlineSpec (..)) #endif -import           Clash.Core.DataCon          (dcExtTyVars)- #if EXPERIMENTAL_EVALUATOR import           Clash.Core.PartialEval import           Clash.Core.PartialEval.NormalForm@@ -83,14 +81,8 @@   (substTmEnv, aeqTerm, aeqType, extendIdSubst, mkSubst, substTm) import           Clash.Core.Term import           Clash.Core.TermInfo-import           Clash.Core.TyCon-  (TyConMap, tyConDataCons)-import           Clash.Core.Type             (KindOrType, Type (..),-                                              TypeView (..), coreView1,-                                              normalizeType,-                                              typeKind, tyView)-import           Clash.Core.Util-  (dataConInstArgTysE)+import           Clash.Core.TyCon            (TyConMap)+import           Clash.Core.Type             (Type (..), normalizeType, typeKind) import           Clash.Core.Var   (Id, IdScope (..), TyVar, Var (..), mkGlobalId, mkLocalId, mkTyVar) import           Clash.Core.VarEnv@@ -366,19 +358,6 @@   let ki = typeKind tcm ty   return (Right (mkTyVar ki (coerce name'))) --- | Make a new, unique, identifier-mkInternalVar-  :: (MonadUnique m)-  => InScopeSet-  -> OccName-  -- ^ Name of the identifier-  -> KindOrType-  -> m Id-mkInternalVar inScope name ty = do-  i <- getUniqueM-  let nm = mkUnsafeInternalName name i-  return (uniqAway inScope (mkLocalId ty nm))- -- | Inline the binders in a let-binding that have a certain property inlineBinders   :: (Term -> LetBinding -> RewriteMonad extra Bool)@@ -741,49 +720,6 @@                              <*> pure stringRepresentable                              <*> Lens.view tcCache                              <*> pure ty)---- | Make a binder that should not be referenced-mkWildValBinder-  :: (MonadUnique m)-  => InScopeSet-  -> Type-  -> m Id-mkWildValBinder is = mkInternalVar is "wild"---- | Make a case-decomposition that extracts a field out of a (Sum-of-)Product type-mkSelectorCase-  :: HasCallStack-  => (Functor m, MonadUnique m)-  => String -- ^ Name of the caller of this function-  -> InScopeSet-  -> TyConMap -- ^ TyCon cache-  -> Term -- ^ Subject of the case-composition-  -> Int -- n'th DataCon-  -> Int -- n'th field-  -> m Term-mkSelectorCase caller inScope tcm scrut dcI fieldI = go (termType tcm scrut)-  where-    go (coreView1 tcm -> Just ty') = go ty'-    go scrutTy@(tyView -> TyConApp tc args) =-      case tyConDataCons (lookupUniqMap' tcm tc) of-        [] -> cantCreate $(curLoc) ("TyCon has no DataCons: " ++ show tc ++ " " ++ showPpr tc) scrutTy-        dcs | dcI > length dcs -> cantCreate $(curLoc) "DC index exceeds max" scrutTy-            | otherwise -> do-          let dc = indexNote ($(curLoc) ++ "No DC with tag: " ++ show (dcI-1)) dcs (dcI-1)-          let (Just fieldTys) = dataConInstArgTysE inScope tcm dc args-          if fieldI >= length fieldTys-            then cantCreate $(curLoc) "Field index exceed max" scrutTy-            else do-              wildBndrs <- mapM (mkWildValBinder inScope) fieldTys-              let ty = indexNote ($(curLoc) ++ "No DC field#: " ++ show fieldI) fieldTys fieldI-              selBndr <- mkInternalVar inScope "sel" ty-              let bndrs  = take fieldI wildBndrs ++ [selBndr] ++ drop (fieldI+1) wildBndrs-                  pat    = DataPat dc (dcExtTyVars dc) bndrs-                  retVal = Case scrut ty [ (pat, Var selBndr) ]-              return retVal-    go scrutTy = cantCreate $(curLoc) ("Type of subject is not a datatype: " ++ showPpr scrutTy) scrutTy--    cantCreate loc info scrutTy = error $ loc ++ "Can't create selector " ++ show (caller,dcI,fieldI) ++ " for: (" ++ showPpr scrut ++ " :: " ++ showPpr scrutTy ++ ")\nAdditional info: " ++ info  -- | Specialise an application on its argument specialise :: Lens' extra (Map.Map (Id, Int, Either Term Type) Id) -- ^ Lens into previous specialisations