packages feed

clash-lib 1.2.0 → 1.2.1

raw patch · 39 files changed

+1700/−1289 lines, 39 filesdep ~basedep ~clash-preludedep ~extraPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, clash-prelude, extra, time

API changes (from Hackage documentation)

- Clash.Core.Util: AbsurdSolution :: TypeEqSolution
- Clash.Core.Util: NoSolution :: TypeEqSolution
- Clash.Core.Util: Solution :: (TyVar, Type) -> TypeEqSolution
- Clash.Core.Util: altEqs :: TyConMap -> Alt -> [(Type, Type)]
- Clash.Core.Util: applyTypeToArgs :: Term -> TyConMap -> Type -> [Either Term Type] -> Type
- Clash.Core.Util: catSolutions :: [TypeEqSolution] -> [(TyVar, Type)]
- Clash.Core.Util: collectBndrs :: Term -> ([Either Id TyVar], Term)
- Clash.Core.Util: data TypeEqSolution
- Clash.Core.Util: idToVar :: Id -> Term
- Clash.Core.Util: instance GHC.Classes.Eq Clash.Core.Util.TypeEqSolution
- Clash.Core.Util: instance GHC.Show.Show Clash.Core.Util.TypeEqSolution
- Clash.Core.Util: isAbsurdAlt :: TyConMap -> Alt -> Bool
- Clash.Core.Util: isAbsurdEq :: TyConMap -> (Type, Type) -> Bool
- Clash.Core.Util: isCon :: Term -> Bool
- Clash.Core.Util: isFun :: TyConMap -> Term -> Bool
- Clash.Core.Util: isLam :: Term -> Bool
- Clash.Core.Util: isLet :: Term -> Bool
- Clash.Core.Util: isLocalVar :: Term -> Bool
- Clash.Core.Util: isPolyFun :: TyConMap -> Term -> Bool
- Clash.Core.Util: isPrim :: Term -> Bool
- Clash.Core.Util: isVar :: Term -> Bool
- Clash.Core.Util: mkAbstraction :: Term -> [Either Id TyVar] -> Term
- Clash.Core.Util: mkApps :: Term -> [Either Term Type] -> Term
- Clash.Core.Util: mkLams :: Term -> [Id] -> Term
- Clash.Core.Util: mkTicks :: Term -> [TickInfo] -> Term
- Clash.Core.Util: mkTmApps :: Term -> [Term] -> Term
- Clash.Core.Util: mkTyApps :: Term -> [Type] -> Term
- Clash.Core.Util: mkTyLams :: Term -> [TyVar] -> Term
- Clash.Core.Util: normalizeAdd :: (Type, Type) -> Maybe (Integer, Integer, Type)
- Clash.Core.Util: patIds :: Pat -> ([TyVar], [Id])
- Clash.Core.Util: patVars :: Pat -> [Var a]
- Clash.Core.Util: piResultTy :: HasCallStack => TyConMap -> Type -> Type -> Type
- Clash.Core.Util: piResultTyMaybe :: HasCallStack => TyConMap -> Type -> Type -> Maybe Type
- Clash.Core.Util: piResultTys :: HasCallStack => TyConMap -> Type -> [Type] -> Type
- Clash.Core.Util: solveAdd :: (Type, Type) -> TypeEqSolution
- Clash.Core.Util: solveEq :: TyConMap -> (Type, Type) -> [TypeEqSolution]
- Clash.Core.Util: solveNonAbsurds :: TyConMap -> [(Type, Type)] -> [(TyVar, Type)]
- Clash.Core.Util: stripTicks :: Term -> Term
- Clash.Core.Util: substGlobalsInExistentials :: HasCallStack => InScopeSet -> [TyVar] -> [(TyVar, Type)] -> [TyVar]
- Clash.Core.Util: substInExistentials :: HasCallStack => InScopeSet -> [TyVar] -> (TyVar, Type) -> [TyVar]
- Clash.Core.Util: substInExistentialsList :: HasCallStack => InScopeSet -> [TyVar] -> [(TyVar, Type)] -> [TyVar]
- Clash.Core.Util: termSize :: Term -> Word
- Clash.Core.Util: termType :: TyConMap -> Term -> Type
- Clash.Core.Util: type Delta = VarEnv Kind
- Clash.Core.Util: type Gamma = VarEnv Type
- Clash.Core.Util: typeEq :: TyConMap -> Type -> Maybe (Type, Type)
- Clash.Core.Util: varToId :: Term -> Id
- Clash.Driver.Types: [succesFlags] :: Manifest -> (Int, Int, Bool)
- Clash.Util: (<$>) :: Functor f => (a -> b) -> f a -> f b
- Clash.Util: (<*>) :: Applicative f => f (a -> b) -> f a -> f b
- Clash.Util: (<:>) :: Applicative f => f a -> f [a] -> f [a]
- Clash.Util: allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
- Clash.Util: anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool
- Clash.Util: class Functor f => Applicative (f :: Type -> Type)
- Clash.Util: concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
- Clash.Util: countEq :: Eq a => a -> [a] -> Int
- Clash.Util: debugIsOn :: Bool
- Clash.Util: equalLength :: [a] -> [b] -> Bool
- Clash.Util: filterOnFst :: (a -> Bool) -> [(a, b)] -> [b]
- Clash.Util: filterOnSnd :: (b -> Bool) -> [(a, b)] -> [a]
- Clash.Util: firstM :: Functor f => (a -> f c) -> (a, b) -> f (c, b)
- Clash.Util: headMaybe :: [a] -> Maybe a
- Clash.Util: ifThenElse :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b
- Clash.Util: indexMaybe :: [a] -> Int -> Maybe a
- Clash.Util: infixl 4 <$>
- Clash.Util: infixr 5 <:>
- Clash.Util: liftState :: MonadState s m => Lens' s s' -> State s' a -> m a
- Clash.Util: mapAccumLM :: Monad m => (acc -> x -> m (acc, y)) -> acc -> [x] -> m (acc, [y])
- Clash.Util: neLength :: [a] -> [b] -> Bool
- Clash.Util: orM :: Monad m => [m Bool] -> m Bool
- Clash.Util: partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
- Clash.Util: pure :: Applicative f => a -> f a
- Clash.Util: secondM :: Functor f => (b -> f c) -> (a, b) -> f (a, c)
- Clash.Util: splitAtList :: [b] -> [a] -> ([a], [a])
- Clash.Util: tailMaybe :: [a] -> Maybe [a]
- Clash.Util: traceIf :: Bool -> String -> a -> a
- Clash.Util: traceShowWith :: Show b => (a -> b) -> a -> a
- Clash.Util: traceWith :: (a -> String) -> a -> a
- Clash.Util: uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
- Clash.Util: zipEqual :: [a] -> [b] -> [(a, b)]
+ Clash.Backend.Verilog: Contiguous :: Int -> Int -> Range
+ Clash.Backend.Verilog: Split :: [(Int, Int, Provenance)] -> Range
+ Clash.Backend.Verilog: continueWithRange :: [(Int, Int)] -> HWType -> Range -> (Range, HWType)
+ Clash.Backend.Verilog: data Range
+ Clash.Core.EqSolver: AbsurdSolution :: TypeEqSolution
+ Clash.Core.EqSolver: NoSolution :: TypeEqSolution
+ Clash.Core.EqSolver: Solution :: (TyVar, Type) -> TypeEqSolution
+ Clash.Core.EqSolver: altEqs :: TyConMap -> Alt -> [(Type, Type)]
+ Clash.Core.EqSolver: catSolutions :: [TypeEqSolution] -> [(TyVar, Type)]
+ Clash.Core.EqSolver: data TypeEqSolution
+ Clash.Core.EqSolver: instance GHC.Classes.Eq Clash.Core.EqSolver.TypeEqSolution
+ Clash.Core.EqSolver: instance GHC.Show.Show Clash.Core.EqSolver.TypeEqSolution
+ Clash.Core.EqSolver: isAbsurdAlt :: TyConMap -> Alt -> Bool
+ Clash.Core.EqSolver: isAbsurdEq :: TyConMap -> (Type, Type) -> Bool
+ Clash.Core.EqSolver: normalizeAdd :: (Type, Type) -> Maybe (Integer, Integer, Type)
+ Clash.Core.EqSolver: solveAdd :: (Type, Type) -> TypeEqSolution
+ Clash.Core.EqSolver: solveEq :: TyConMap -> (Type, Type) -> [TypeEqSolution]
+ Clash.Core.EqSolver: solveNonAbsurds :: TyConMap -> [(Type, Type)] -> [(TyVar, Type)]
+ Clash.Core.EqSolver: typeEq :: TyConMap -> Type -> Maybe (Type, Type)
+ Clash.Core.Subst: substGlobalsInExistentials :: HasCallStack => InScopeSet -> [TyVar] -> [(TyVar, Type)] -> [TyVar]
+ Clash.Core.Subst: substInExistentials :: HasCallStack => InScopeSet -> [TyVar] -> (TyVar, Type) -> [TyVar]
+ Clash.Core.Subst: substInExistentialsList :: HasCallStack => InScopeSet -> [TyVar] -> [(TyVar, Type)] -> [TyVar]
+ Clash.Core.Term: collectBndrs :: Term -> ([Either Id TyVar], Term)
+ Clash.Core.Term: idToVar :: Id -> Term
+ Clash.Core.Term: mkAbstraction :: Term -> [Either Id TyVar] -> Term
+ Clash.Core.Term: mkApps :: Term -> [Either Term Type] -> Term
+ Clash.Core.Term: mkLams :: Term -> [Id] -> Term
+ Clash.Core.Term: mkTicks :: Term -> [TickInfo] -> Term
+ Clash.Core.Term: mkTmApps :: Term -> [Term] -> Term
+ Clash.Core.Term: mkTyApps :: Term -> [Type] -> Term
+ Clash.Core.Term: mkTyLams :: Term -> [TyVar] -> Term
+ Clash.Core.Term: patIds :: Pat -> ([TyVar], [Id])
+ Clash.Core.Term: patVars :: Pat -> [Var a]
+ Clash.Core.Term: stripTicks :: Term -> Term
+ Clash.Core.Term: varToId :: Term -> Id
+ Clash.Core.TermInfo: applyTypeToArgs :: Term -> TyConMap -> Type -> [Either Term Type] -> Type
+ Clash.Core.TermInfo: isCon :: Term -> Bool
+ Clash.Core.TermInfo: isFun :: TyConMap -> Term -> Bool
+ Clash.Core.TermInfo: isLam :: Term -> Bool
+ Clash.Core.TermInfo: isLet :: Term -> Bool
+ Clash.Core.TermInfo: isLocalVar :: Term -> Bool
+ Clash.Core.TermInfo: isPolyFun :: TyConMap -> Term -> Bool
+ Clash.Core.TermInfo: isPrim :: Term -> Bool
+ Clash.Core.TermInfo: isVar :: Term -> Bool
+ Clash.Core.TermInfo: piResultTy :: HasCallStack => TyConMap -> Type -> Type -> Type
+ Clash.Core.TermInfo: piResultTyMaybe :: HasCallStack => TyConMap -> Type -> Type -> Maybe Type
+ Clash.Core.TermInfo: piResultTys :: HasCallStack => TyConMap -> Type -> [Type] -> Type
+ Clash.Core.TermInfo: termSize :: Term -> Word
+ Clash.Core.TermInfo: termType :: TyConMap -> Term -> Type
+ Clash.Debug: debugIsOn :: Bool
+ Clash.Debug: traceIf :: Bool -> String -> a -> a
+ Clash.Debug: traceShowWith :: Show b => (a -> b) -> a -> a
+ Clash.Debug: traceWith :: (a -> String) -> a -> a
+ Clash.Driver.Types: [successFlags] :: Manifest -> (Int, Int, Bool)
+ Data.List.Extra: (<:>) :: Applicative f => f a -> f [a] -> f [a]
+ Data.List.Extra: allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+ Data.List.Extra: anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+ Data.List.Extra: countEq :: Eq a => a -> [a] -> Int
+ Data.List.Extra: equalLength :: [a] -> [b] -> Bool
+ Data.List.Extra: indexMaybe :: [a] -> Int -> Maybe a
+ Data.List.Extra: infixr 5 <:>
+ Data.List.Extra: mapAccumLM :: Monad m => (acc -> x -> m (acc, y)) -> acc -> [x] -> m (acc, [y])
+ Data.List.Extra: orM :: Monad m => [m Bool] -> m Bool
+ Data.List.Extra: partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
+ Data.List.Extra: splitAtList :: [b] -> [a] -> ([a], [a])
+ Data.List.Extra: zipEqual :: [a] -> [b] -> [(a, b)]
- Clash.Netlist.BlackBox: mkArgument :: Identifier -> Term -> NetlistMonad ((Expr, HWType, Bool), [Declaration])
+ Clash.Netlist.BlackBox: mkArgument :: Text -> Identifier -> Int -> Term -> NetlistMonad ((Expr, HWType, Bool), [Declaration])
- Clash.Rewrite.Types: bindings :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) BindingMap
+ Clash.Rewrite.Types: bindings :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) BindingMap
- Clash.Rewrite.Types: curFun :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) (Id, SrcSpan)
+ Clash.Rewrite.Types: curFun :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) (Id, SrcSpan)
- Clash.Rewrite.Types: extra :: forall extra_a3wDl extra_a3wLI. Lens (RewriteState extra_a3wDl) (RewriteState extra_a3wLI) extra_a3wDl extra_a3wLI
+ Clash.Rewrite.Types: extra :: forall extra_a3r1P extra_a3rai. Lens (RewriteState extra_a3r1P) (RewriteState extra_a3rai) extra_a3r1P extra_a3rai
- Clash.Rewrite.Types: globalHeap :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) PrimHeap
+ Clash.Rewrite.Types: globalHeap :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) PrimHeap
- Clash.Rewrite.Types: nameCounter :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) Int
+ Clash.Rewrite.Types: nameCounter :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) Int
- Clash.Rewrite.Types: transformCounter :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) Int
+ Clash.Rewrite.Types: transformCounter :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) Int
- Clash.Rewrite.Types: uniqSupply :: forall extra_a3wDl. Lens' (RewriteState extra_a3wDl) Supply
+ Clash.Rewrite.Types: uniqSupply :: forall extra_a3r1P. Lens' (RewriteState extra_a3r1P) Supply
- Clash.Util: on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
+ Clash.Util: on :: () => (b -> b -> c) -> (a -> b) -> a -> a -> c
- Data.Text.Prettyprint.Doc.Extra: layoutCompact :: Doc ann -> SimpleDocStream ann
+ Data.Text.Prettyprint.Doc.Extra: layoutCompact :: () => Doc ann -> SimpleDocStream ann
- Data.Text.Prettyprint.Doc.Extra: layoutPretty :: LayoutOptions -> Doc ann -> SimpleDocStream ann
+ Data.Text.Prettyprint.Doc.Extra: layoutPretty :: () => LayoutOptions -> Doc ann -> SimpleDocStream ann
- Data.Text.Prettyprint.Doc.Extra: renderLazy :: SimpleDocStream ann -> Text
+ Data.Text.Prettyprint.Doc.Extra: renderLazy :: () => SimpleDocStream ann -> Text

Files

CHANGELOG.md view
@@ -1,5 +1,23 @@ # Changelog for the Clash project +## 1.2.1 *April 23rd 2020*+* Changed:+ * Treat `Signed 0`, `Unsigned 0`, `Index 1`, `BitVector 0` as unit. In effect this means that 'minBound' and 'maxBound' return 0, whereas previously they might crash [#1183](https://github.com/clash-lang/clash-compiler/issues/1183)+ * Infix use of `deepseqX` is now right-associative++* Added:+  * Add 'natToInteger', 'natToNatural', and 'natToNum'. Similar to 'snatTo*', but works solely on a type argument instead of an SNat.+  * `Clash.Sized.Vector.unfoldr` and `Clash.Sized.Vector.unfoldrI` to construct vectors from a seed value+  * Added NFDataX instances for `Data.Monoid.{First,Last}`++* Fixed:+ * The Verilog backend can now deal with non-contiguous ranges in custom bit-representations.+ * Synthesizing BitPack instances for type with phantom parameter fails [#1242](https://github.com/clash-lang/clash-compiler/issues/1242)+ * Synthesis of `fromBNat (toBNat d5)` failed due to `unsafeCoerce` coercing from `Any`+ * Memory leak in register primitives [#1256](https://github.com/clash-lang/clash-compiler/issues/1256)+ * Illegal VHDL slice when projecting nested SOP type [#1254](https://github.com/clash-lang/clash-compiler/issues/1254)+ * Vivado VHDL code path (`-fclash-hdlsyn Vivado`) generates illegal VHDL [#1264](https://github.com/clash-lang/clash-compiler/issues/1264)+ ## 1.2.0 *March 5th 2020* As promised when releasing 1.0, we've tried our best to keep the API stable. We think most designs will continue to compile with this new version, although special
clash-lib.cabal view
@@ -1,6 +1,6 @@ Cabal-version:        2.2 Name:                 clash-lib-Version:              1.2.0+Version:              1.2.1 Synopsis:             CAES Language for Synchronous Hardware - As a Library Description:   Clash is a functional hardware description language that borrows both its@@ -120,7 +120,7 @@   import:             common-options   HS-Source-Dirs:     src -  ghc-options:        -Wall+  ghc-options:        -Wall -Wcompat   CPP-Options:        -DCABAL    other-extensions:   CPP@@ -138,10 +138,10 @@   Build-depends:      aeson                   >= 0.6.2.0  && < 1.5,                       ansi-terminal           >= 0.8.0.0  && < 0.11,                       attoparsec              >= 0.10.4.0 && < 0.14,-                      base                    >= 4.10     && < 5,+                      base                    >= 4.11     && < 5,                       binary                  >= 0.8.5    && < 0.11,                       bytestring              >= 0.10.0.2 && < 0.11,-                      clash-prelude           == 1.2.0,+                      clash-prelude           == 1.2.1,                       concurrent-supply       >= 0.1.7    && < 0.2,                       containers              >= 0.5.0.0  && < 0.7,                       data-binary-ieee754     >= 0.4.4    && < 0.6,@@ -151,7 +151,7 @@                       directory               >= 1.2.0.1  && < 1.4,                       errors                  >= 1.4.2    && < 2.4,                       exceptions              >= 0.8.3    && < 0.11.0,-                      extra                   >= 1.6.18   && < 1.7,+                      extra                   >= 1.6.18   && < 1.8,                       filepath                >= 1.3.0.1  && < 1.5,                       ghc                     >= 8.4.0    && < 8.9,                       ghc-boot-th,@@ -172,7 +172,7 @@                       temporary               >= 1.2.1    && < 1.4,                       text                    >= 1.2.2    && < 1.3,                       text-show               >= 3.7      && < 3.9,-                      time                    >= 1.4.0.1  && < 1.10,+                      time                    >= 1.4.0.1  && < 1.11,                       transformers            >= 0.5.2.0  && < 0.6,                       trifecta                >= 1.7.1.1  && < 2.2,                       vector                  >= 0.11     && < 1.0,@@ -189,6 +189,7 @@                       Clash.Backend.VHDL                        Clash.Core.DataCon+                      Clash.Core.EqSolver                       Clash.Core.Evaluator                       Clash.Core.Evaluator.Types                       Clash.Core.FreeVars@@ -197,6 +198,7 @@                       Clash.Core.Pretty                       Clash.Core.Subst                       Clash.Core.Term+                      Clash.Core.TermInfo                       Clash.Core.TermLiteral                       Clash.Core.TermLiteral.TH                       Clash.Core.TyCon@@ -206,6 +208,8 @@                       Clash.Core.Var                       Clash.Core.VarEnv +                      Clash.Debug+                       Clash.Driver                       Clash.Driver.Types @@ -246,6 +250,7 @@                       Clash.Util.Interpolate                       Clash.Pretty +                      Data.List.Extra                       Data.Text.Prettyprint.Doc.Extra    Other-Modules:      Clash.Annotations.TopEntity.Extra@@ -268,7 +273,7 @@   type:             exitcode-stdio-1.0   default-language: Haskell2010   main-is:          unittests.hs-  ghc-options:      -Wall+  ghc-options:      -Wall -Wcompat   hs-source-dirs:   tests    if !flag(unittests)
+ prims/common/Clash_Signal_Trace.json view
@@ -0,0 +1,67 @@+[ { "BlackBox" :+    { "name"      : "Clash.Signal.Trace.traceSignal1"+    , "workInfo"  : "Never"+    , "kind"      : "Expression"+    , "type"      :+"traceSignal1+  :: ( BitPack a    -- ARG[0]+     , NFDataX a    -- ARG[1]+     , Typeable a ) -- ARG[2]+  => String         -- ARG[3]+  -> Signal dom a   -- ARG[4]+  -> Signal dom a"+    , "template" : "~ARG[4]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Signal.Trace.traceVecSignal1"+    , "workInfo"  : "Never"+    , "kind"      : "Expression"+    , "type"      :+"traceVecSignal1+  :: ( KnownNat n             -- ARG[0]+     , BitPack a              -- ARG[1]+     , NFDataX a              -- ARG[2]+     , Typeable a )           -- ARG[3]+  => String                   -- ARG[4]+  -> Signal dom (Vec (n+1) a) -- ARG[5]+  -> Signal dom (Vec (n+1) a)"+    , "template" : "~ARG[5]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Signal.Trace.traceSignal"+    , "workInfo"  : "Never"+    , "kind"      : "Expression"+    , "type"      :+"traceSignal+  :: forall dom a+   . ( KnownDomain dom -- ARG[0]+     , BitPack a       -- ARG[1]+     , NFDataX a       -- ARG[2]+     , Typeable a )    -- ARG[3]+  => String            -- ARG[4]+  -> Signal dom a      -- ARG[5]+  -> Signal dom a"+    , "template" : "~ARG[5]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Signal.Trace.traceVecSignal"+    , "workInfo"  : "Never"+    , "kind"      : "Expression"+    , "type"      :+"traceVecSignal+  :: forall dom a n+   . ( KnownDomain dom        -- ARG[0]+     , KnownNat n             -- ARG[1]+     , BitPack a              -- ARG[2]+     , NFDataX a              -- ARG[3]+     , Typeable a )           -- ARG[4]+  => String                   -- ARG[5]+  -> Signal dom (Vec (n+1) a) -- ARG[6]+  -> Signal dom (Vec (n+1) a)"+    , "template" : "~ARG[6]"+    }+  }+]
prims/common/Clash_Sized_Internal_Unsigned.json view
@@ -19,4 +19,28 @@     , "template"  : "~ARG[0] / ~ARG[1]"     }   }+, { "BlackBox" :+    { "name"      : "Clash.Sized.Internal.Unsigned.unsignedToWord"+    , "kind"      : "Expression"+    , "template"  : "~ARG[0]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Sized.Internal.Unsigned.unsigned8toWord8"+    , "kind"      : "Expression"+    , "template"  : "~ARG[0]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Sized.Internal.Unsigned.unsigned16toWord16"+    , "kind"      : "Expression"+    , "template"  : "~ARG[0]"+    }+  }+, { "BlackBox" :+    { "name"      : "Clash.Sized.Internal.Unsigned.unsigned32toWord32"+    , "kind"      : "Expression"+    , "template"  : "~ARG[0]"+    }+  } ]
prims/commonverilog/Clash_Sized_Internal_BitVector.json view
@@ -325,22 +325,22 @@ , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.and#"     , "kind"      : "Expression"-    , "type"      : "and# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] & ~ARG[1]"+    , "type"      : "and# :: KnownNat n => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] & ~ARG[2]"     }   } , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.or#"     , "kind"      : "Expression"-    , "type"      : "or# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] | ~ARG[1]"+    , "type"      : "or# :: KnownNat n => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] | ~ARG[2]"     }   } , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.xor#"     , "kind"      : "Expression"-    , "type"      : "xor# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] ^ ~ARG[1]"+    , "type"      : "xor# :: KnownNat => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] ^ ~ARG[2]"     }   } , { "BlackBox" :
prims/systemverilog/Clash_Sized_Internal_BitVector.json view
@@ -21,16 +21,17 @@     , "workInfo" : "Never"     , "kind" : "Declaration"     , "type" :-"setSlice# :: BitVector (m + 1 + i) -- ARG[0]-           -> SNat m                -- ARG[1]-           -> SNat n                -- ARG[2]-           -> BitVector (m + 1 - n) -- ARG[3]+"setSlice# :: SNat (m + 1 + i)+           -> BitVector (m + 1 + i) -- ARG[1]+           -> SNat m                -- ARG[2]+           -> SNat n                -- ARG[3]+           -> BitVector (m + 1 - n) -- ARG[4]            -> BitVector (m + 1 + i)"     , "template" : "// setSlice begin always_comb begin-  ~RESULT = ~ARG[0];-  ~RESULT[~LIT[1] : ~LIT[2]] = ~ARG[3];+  ~RESULT = ~ARG[1];+  ~RESULT[~LIT[2] : ~LIT[3]] = ~ARG[4]; end // setSlice end"     }
prims/verilog/Clash_Sized_Internal_BitVector.json view
@@ -22,17 +22,18 @@     , "workInfo" : "Never"     , "kind" : "Declaration"     , "type" :-"setSlice# :: BitVector (m + 1 + i) -- ARG[0]-           -> SNat m                -- ARG[1]-           -> SNat n                -- ARG[2]-           -> BitVector (m + 1 - n) -- ARG[3]+"setSlice# :: SNat (m + 1 + i)+           -> BitVector (m + 1 + i) -- ARG[1]+           -> SNat m                -- ARG[2]+           -> SNat n                -- ARG[3]+           -> BitVector (m + 1 - n) -- ARG[4]            -> BitVector (m + 1 + i)"     , "outputReg" : true     , "template" : "// setSlice begin always @(*) begin-  ~RESULT = ~ARG[0];-  ~RESULT[~LIT[1] : ~LIT[2]] = ~VAR[din][3];+  ~RESULT = ~ARG[1];+  ~RESULT[~LIT[2] : ~LIT[3]] = ~VAR[din][4]; end // setSlice end"     }
prims/vhdl/Clash_Explicit_BlockRam.json view
@@ -73,8 +73,9 @@   -> Signal dom a"     , "template" : "-- blockRamU begin-~GENSYM[~RESULT_blockRam][1] : block-  type ~GENSYM[ram_t][8] is array (0 to integer'(~LIT[5])-1) of ~TYP[9];+~GENSYM[~RESULT_blockRam][1] : block~IF~VIVADO~THEN+  type ~GENSYM[ram_t][8] is array (0 to integer'(~LIT[5])-1) of std_logic_vector(~SIZE[~TYP[9]]-1 downto 0);~ELSE+  type ~SYM[8] is array (0 to integer'(~LIT[5])-1) of ~TYP[9];~FI   signal ~GENSYM[~RESULT_RAM][2] : ~SYM[8];   signal ~GENSYM[rd][4]  : integer range 0 to ~LIT[5] - 1;   signal ~GENSYM[wr][5]  : integer range 0 to ~LIT[5] - 1;@@ -132,9 +133,10 @@   -> Signal dom a"     , "template" : "-- blockRam1 begin-~GENSYM[~RESULT_blockRam][1] : block-  type ~GENSYM[ram_t][8] is array (0 to integer'(~LIT[5])-1) of ~TYP[6];-  signal ~GENSYM[~RESULT_RAM][2] : ~SYM[8] := (others => ~CONST[6]);+~GENSYM[~RESULT_blockRam][1] : block~IF~VIVADO~THEN+  type ~GENSYM[ram_t][8] is array (0 to integer'(~LIT[5])-1) of std_logic_vector(~SIZE[~TYP[6]]-1 downto 0);~ELSE+  type ~SYM[8] is array (0 to integer'(~LIT[5])-1) of ~TYP[6];~FI+  signal ~GENSYM[~RESULT_RAM][2] : ~SYM[8] := (others => ~IF~VIVADO~THEN~TOBV[~CONST[6]][~TYP[6]]~ELSE~CONST[6]~FI);   signal ~GENSYM[rd][4]  : integer range 0 to ~LIT[5] - 1;   signal ~GENSYM[wr][5]  : integer range 0 to ~LIT[5] - 1; begin
prims/vhdl/Clash_Sized_Internal_BitVector.json view
@@ -301,18 +301,19 @@     , "workInfo" : "Never"     , "kind" : "Declaration"     , "type" :-"setSlice# :: BitVector (m + 1 + i) -- ARG[0]-           -> SNat m                -- ARG[1]-           -> SNat n                -- ARG[2]-           -> BitVector (m + 1 - n) -- ARG[3]+"setSlice# :: SNat (m + 1 + i)+           => BitVector (m + 1 + i) -- ARG[1]+           -> SNat m                -- ARG[2]+           -> SNat n                -- ARG[3]+           -> BitVector (m + 1 - n) -- ARG[4]            -> BitVector (m + 1 + i)"     , "template" : "-- setSlice begin-~GENSYM[setSlice][0] : process(~VAR[bv][0]~VARS[3])+~GENSYM[setSlice][0] : process(~VAR[bv][0]~VARS[4])   variable ~GENSYM[ivec][1] : ~TYP[0]; begin-  ~SYM[1] := ~ARG[0];-  ~SYM[1](~LIT[1] downto ~LIT[2]) := ~VAR[bv][3];+  ~SYM[1] := ~ARG[1];+  ~SYM[1](~LIT[2] downto ~LIT[3]) := ~VAR[bv][4];   ~RESULT <= ~SYM[1]; end process; -- setSlice end"@@ -500,22 +501,22 @@ , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.and#"     , "kind"      : "Expression"-    , "type"      : "and# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] and ~ARG[1]"+    , "type"      : "and# :: KnownNat n => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] and ~ARG[2]"     }   } , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.or#"     , "kind"      : "Expression"-    , "type"      : "or# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] or ~ARG[1]"+    , "type"      : "or# :: KnownNat n => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] or ~ARG[2]"     }   } , { "BlackBox" :     { "name"      : "Clash.Sized.Internal.BitVector.xor#"     , "kind"      : "Expression"-    , "type"      : "xor# :: BitVector n -> BitVector n -> BitVector n"-    , "template"  : "~ARG[0] xor ~ARG[1]"+    , "type"      : "xor# :: KnownNat n => BitVector n -> BitVector n -> BitVector n"+    , "template"  : "~ARG[1] xor ~ARG[2]"     }   } , { "BlackBox" :
prims/vhdl/Clash_Sized_RTree.json view
@@ -3,7 +3,7 @@     , "workInfo"  : "Never"     , "kind"      : "Expression"     , "type"      : "replicate :: SNat n -> a -> RTree d a"-    , "template"  : "~TYPMO'(0 to (2**~LIT[0])-1 => ~ARG[1])"+    , "template"  : "~TYPMO'(0 to (2**~LIT[0])-1 => ~IF~VIVADO~THEN~TOBV[~TYPM[1]'(~ARG[1])][~TYP[1]]~ELSE~ARG[1]~FI)"     }   } , { "BlackBox" :@@ -11,7 +11,7 @@     , "workInfo"  : "Never"     , "kind"      : "Expression"     , "type"      : "textract :: RTree 0 a -> a"-    , "template"  : "~IF ~VIVADO ~THEN ~FROMBV[~VAR[t][0]][~TYPO] ~ELSE ~VAR[t][0](0) ~FI"+    , "template"  : "~IF ~VIVADO ~THEN ~FROMBV[~VAR[t][0](0)][~TYPO] ~ELSE ~VAR[t][0](0) ~FI"     }   } , { "BlackBox" :
src/Clash/Backend/SystemVerilog.hs view
@@ -27,6 +27,7 @@ import           Data.HashSet                         (HashSet) import qualified Data.HashSet                         as HashSet import           Data.List                            (nub, nubBy)+import           Data.List.Extra                      ((<:>)) import           Data.Maybe                           (catMaybes,fromMaybe,mapMaybe) #if !MIN_VERSION_base(4,11,0) import           Data.Monoid                          hiding (Sum, Product)@@ -45,6 +46,7 @@ import           Clash.Annotations.BitRepresentation.Util   (BitOrigin(Lit, Field), bitOrigins, bitRanges) import           Clash.Core.Var                       (Attr'(..))+import           Clash.Debug                          (traceIf) import           Clash.Backend import           Clash.Backend.Verilog   (bits, bit_char, encodingNote, exprLit, include, noEmptyInit, uselibs)@@ -56,7 +58,7 @@ import           Clash.Netlist.Util                   hiding (mkIdentifier, extendIdentifier) import           Clash.Signal.Internal                (ActiveEdge (..)) import           Clash.Util-  (SrcSpan, noSrcSpan, curLoc, makeCached, (<:>), first, on, traceIf, indexNote)+  (SrcSpan, noSrcSpan, curLoc, makeCached, first, on, indexNote) import           Clash.Util.Graph                     (reverseTopSort)  -- | State for the 'Clash.Backend.SystemVerilog.SystemVerilogM' monad:
src/Clash/Backend/VHDL.hs view
@@ -31,6 +31,7 @@ import qualified Data.HashSet                         as HashSet import           Data.List   (mapAccumL, nub, nubBy, intersperse, group, sort)+import           Data.List.Extra                      ((<:>), equalLength) import           Data.Maybe                           (catMaybes,fromMaybe,mapMaybe) #if !MIN_VERSION_base(4,11,0) import           Data.Monoid                          hiding (Sum, Product)@@ -54,6 +55,7 @@   (BitOrigin(Lit, Field), bitOrigins, bitRanges) import           Clash.Backend import           Clash.Core.Var                       (Attr'(..),attrName)+import           Clash.Debug                          (traceIf) import           Clash.Netlist.BlackBox.Types         (HdlSyn (..)) import           Clash.Netlist.BlackBox.Util   (extractLiterals, renderBlackBox, renderFilePath)@@ -61,10 +63,11 @@ import           Clash.Netlist.Types                  hiding (_intWidth, intWidth) import           Clash.Netlist.Util                   hiding (mkIdentifier) import           Clash.Util-  (SrcSpan, noSrcSpan, clogBase, curLoc, first, makeCached, on, traceIf, (<:>),-   indexNote)+  (SrcSpan, noSrcSpan, clogBase, curLoc, first, makeCached, on, indexNote) import           Clash.Util.Graph                     (reverseTopSort) +import           Clash.Backend.Verilog (Range (..), continueWithRange)+ -- | State for the 'Clash.Netlist.VHDL.VHDLM' monad: data VHDLState =   VHDLState@@ -131,9 +134,9 @@   toBV _ id_      = do     nm <- Mon $ use modNm     pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (pretty id_)-  fromBV _ id_  = do+  fromBV t id_  = do     nm <- Mon $ use modNm-    pretty (TextS.toLower nm) <> "_types.fromSLV" <> parens (pretty id_)+    qualTyName t <> "'" <> parens (pretty (TextS.toLower nm) <> "_types.fromSLV" <> parens (pretty id_))   hdlSyn          = use hdlsyn   mkIdentifier    = do       allowExtended <- use extendedIds@@ -1464,222 +1467,10 @@   -> VHDLM Doc expr_ _ (Literal sizeM lit) = exprLit sizeM lit expr_ _ (Identifier id_ Nothing) = pretty id_-expr_ _ (Identifier id_ (Just (Indexed (CustomSP _id dataRepr _size args,dcI,fI)))) =-  case fieldTy of-    Void {} ->-      error (unexpectedProjectionErrorMsg dataRepr dcI fI)-    _ -> do-      nm <- Mon $ use modNm-      let cast = qualTyName resultType <> squote-      let fSLV = stringS (TextS.toLower nm) <> "_types.fromSLV"-      cast <> parens (fSLV <> parens (hcat $ punctuate " & " $ ranges))- where-  resultType = fieldTypes !! fI-  (ConstrRepr' _name _n _mask _value anns, _, fieldTypes) = args !! dcI -  ranges =-    mapM range $ bitRanges (anns !! fI)--  range (start, end) =-    pretty id_ <> parens (int start <+> "downto" <+> int end)--  fieldTy = indexNote ($(curLoc) ++ "panic") fieldTypes fI--expr_ b (Identifier id_ (Just (Indexed (ty@(SP _ args),dcI,fI)))) = do-  nm <- Mon $ use modNm-  case b of-    True ->-      (case normaliseType argTy of-        BitVector {} -> id-        _ -> (\x -> pretty (TextS.toLower nm) <> "_types.fromSLV" <> parens x))-      (pretty id_ <> parens (int start <+> "downto" <+> int end))-    _ -> fromSLV argTy id_ start end- where-   argTys   = snd $ args !! dcI-   argTy    = argTys !! fI-   argSize  = typeSize argTy-   other    = otherSize argTys (fI-1)-   start    = typeSize ty - 1 - conSize ty - other-   end      = start - argSize + 1--expr_ _ (Identifier id_ (Just (Indexed (CustomProduct _ dataRepr _ _ tys, dcI, fI)))) =-  case fieldTy of-    Void {} ->-      error (unexpectedProjectionErrorMsg dataRepr dcI fI)-    _ -> do-      modNm' <- Mon (use modNm)-      let cast = qualTyName fieldTy <> squote-      let fSLV = stringS (TextS.toLower modNm') <> "_types.fromSLV"-      cast <> parens (fSLV <> parens (hcat $ punctuate " & " $ ranges))- where-  (fieldAnn, fieldTy) = indexNote ($(curLoc) ++ "panic") tys fI-  ranges = mapM range (bitRanges fieldAnn)-  range (start, end) = pretty id_ <> parens (int start <+> "downto" <+> int end)--expr_ _ (Identifier id_ (Just (Indexed (ty@(Product _ labels tys),_,fI)))) =-  pretty id_ <> dot <> tyName ty <> selectProductField labels tys fI--expr_ _ (Identifier id_ (Just (Indexed ((Vector _ elTy),1,0)))) = do-  syn <- Mon hdlSyn-  case syn of-    Vivado -> do-      id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int 0))-      fromSLV elTy id' (typeSize elTy - 1) 0-    _ -> pretty id_ <> parens (int 0)-expr_ _ (Identifier id_ (Just (Indexed ((Vector n _),1,1)))) = pretty id_ <> parens (int 1 <+> "to" <+> int (n-1))---- This is a "Hack", we cannot construct trees with a negative depth. This is--- here so that we can recognise merged RTree modifiers. See the code in--- @Clash.Backend.nestM@ which construct these tree modifiers.-expr_ _ (Identifier id_ (Just (Indexed (RTree (-1) _,l,r)))) =-  pretty id_ <> parens (int l <+> "to" <+> int (r-1))--expr_ _ (Identifier id_ (Just (Indexed ((RTree 0 elTy),0,0)))) = do-  syn <- Mon hdlSyn-  case syn of-    Vivado -> do-      id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int 0))-      fromSLV elTy id' (typeSize elTy - 1) 0-    _ -> pretty id_ <> parens (int 0)-expr_ _ (Identifier id_ (Just (Indexed ((RTree n _),1,0)))) =-  let z = 2^(n-1)-  in  pretty id_ <> parens (int 0 <+> "to" <+> int (z-1))-expr_ _ (Identifier id_ (Just (Indexed ((RTree n _),1,1)))) =-  let z  = 2^(n-1)-      z' = 2^n-  in  pretty id_ <> parens (int z <+> "to" <+> int (z'-1))---- This is a HACK for Clash.Driver.TopWrapper.mkOutput--- Vector's don't have a 10'th constructor, this is just so that we can--- recognize the particular case-expr_ _ (Identifier id_ (Just (Indexed ((Vector _ elTy),10,fI)))) = do-  syn <- Mon hdlSyn-  case syn of-    Vivado -> do-      id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int fI))-      fromSLV elTy id' (typeSize elTy - 1) 0-    _ -> pretty id_ <> parens (int fI)---- This is a HACK for Clash.Driver.TopWrapper.mkOutput--- RTree's don't have a 10'th constructor, this is just so that we can--- recognize the particular case-expr_ _ (Identifier id_ (Just (Indexed ((RTree _ elTy),10,fI)))) = do+expr_ _ (Identifier id_ (Just m)) = do   syn <- Mon hdlSyn-  case syn of-    Vivado -> do-      id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int fI))-      fromSLV elTy id' (typeSize elTy - 1) 0-    _ -> pretty id_ <> parens (int fI)--expr_ _ (Identifier id_ (Just (DC (ty@(SP _ _),_)))) = pretty id_ <> parens (int start <+> "downto" <+> int end)-  where-    start = typeSize ty - 1-    end   = typeSize ty - conSize ty---- [Note] integer projection------ The idea behind these expressions is to translate cases like:------ > :: Int8 -> Int#--- > \case I8# i -> i------ Which is fine, because no bits are lost. However, these expression might--- also be the result of the W/W transformation (or uses of unsafeToInteger)--- for:------ > :: Signed 128 -> Integer--- > \case S i -> i------ which is very bad because `Integer` is represented by 64 bits meaning we--- we lose the top 64 bits in the above translation.------ Just as bad is that------ > :: Word8 -> Word#--- > \case W8# w -> w------ > :: Unsigned 8 -> Integer--- > \case U i -> i------ result in the same expression... even though their resulting types are--- different. TODO: this needs  to be fixed!-expr_ _ (Identifier id_ (Just (Indexed ((Signed w),_,_))))  = do-  iw <- Mon $ use intWidth-  traceIf (iw < w) ($(curLoc) ++ "WARNING: result smaller than argument") $-    "resize" <> parens (pretty id_ <> "," <> int iw)-expr_ _ (Identifier id_ (Just (Indexed ((Unsigned w),_,_)))) = do-  iw <- Mon $ use intWidth-  traceIf (iw < w) ($(curLoc) ++ "WARNING: result smaller than argument") $-    "resize" <> parens (pretty id_ <> "," <> int iw)---- [Note] mask projection------ This covers the case of either:------ `Clash.Sized.Internal.BitVector.unsafeToMask` or------ > :: BitVector 8 -> Integer--- > \case BV m wild -> m------ introduced by the W/W transformation. Both of which we prefer not to see--- but will allow. Since the mask is pretty much a simulation artifact we--- emit don't cares so stuff gets optimised away.-expr_ _ (Identifier _ (Just (Indexed ((BitVector _),_,0)))) = do-  iw <- Mon $ use intWidth-  traceIf True ($(curLoc) ++ "WARNING: synthesizing bitvector mask to dontcare") $-    sizedQualTyNameErrValue (Signed iw)---- [Note] bitvector projection------ This covers the case of either:------ `Clash.Sized.Internal.BitVector.unsafeToInteger` or------ > :: BitVector 8 -> Integer--- > \case BV wild i -> i------ introduced by the-expr_ _ (Identifier id_ (Just (Indexed ((BitVector w),_,1)))) = do-  iw <- Mon $ use intWidth-  traceIf (iw < w) ($(curLoc) ++ "WARNING: result smaller than argument") $-    "signed" <> parens ("std_logic_vector" <> parens ("resize" <>-      parens ("unsigned" <> parens (pretty id_) <> "," <> int iw)))--expr_ _ (Identifier id_ (Just (Sliced (BitVector _,start,end)))) =-  pretty id_ <> parens (int start <+> "downto" <+> int end)--expr_ b (Identifier id_ (Just (Nested (Indexed ((Vector n elTy),1,1)) m0))) = go 1 m0- where-  go s (Nested (Indexed ((Vector {}),1,1)) m1) = go (s+1) m1-  go s (Indexed (Vector {},1,1)) = pretty id_ <> parens (int (s+1) <+> "to" <+> int (n-1))-  go s (Indexed (Vector {},1,0)) = do-    syn <- Mon hdlSyn-    case syn of-      Vivado -> do-        id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int s))-        fromSLV elTy id' (typeSize elTy - 1) 0-      _ -> pretty id_ <> parens (int s)-  -- This is a HACK for Clash.Driver.TopWrapper.mkOutput--- Vector's don't have a 10'th constructor, this is just so that we can--- recognize the particular case-  go s (Indexed (Vector {},10,fI)) = do-    syn <- Mon hdlSyn-    case syn of-      Vivado -> do-        id' <- fmap (T.toStrict . renderOneLine) (pretty id_ <> parens (int (s+fI)))-        fromSLV elTy id' (typeSize elTy - 1) 0-      _ -> pretty id_ <> parens (int (s+fI))-  go s m1 = do-    k <- pretty id_ <> parens (int s <+> "to" <+> int (n-1))-    expr b (Identifier (T.toStrict $ renderOneLine k) (Just m1))--expr_ b (Identifier id_ (Just (Nested m1 m2))) = case nestM m1 m2 of-  Just m3 -> expr_ b (Identifier id_ (Just m3))-  _ -> do-    k <- expr_ True (Identifier id_ (Just m1))-    expr_ b (Identifier (T.toStrict $ renderOneLine k) (Just m2))--expr_ _ (Identifier id_ (Just _)) = pretty id_+  maybe (pretty id_) (foldr renderModifier (pretty id_)) (buildModifier syn [] m)  expr_ b (DataCon _ (DC (Void {}, -1)) [e]) =  expr_ b e @@ -1980,15 +1771,16 @@     tName    = tyName t     selNames = map (fmap (T.toStrict . renderOneLine) ) [pretty id_ <> dot <> tName <> selectProductField labels tys i | i <- [0..(length tys)-1]]     selIds   = map (fmap (\n -> Identifier n Nothing)) selNames-toSLV (Product _ _ tys) (DataCon _ _ es) = do+toSLV (Product _ _ tys) (DataCon _ _ es) | equalLength tys es =+  -- Need equalLenght for code seen in ZipWithUnitVector   encloseSep lparen rparen " & " (zipWithM toSLV tys es) toSLV (CustomProduct _ _ _ _ _) e = do   -- Custom representations are represented as bitvectors in HDL, so we don't   -- need to do anything.   expr_ False e-toSLV (Product _ _ _) e = do+toSLV t@(Product _ _ _) e = do   nm <- Mon $ use modNm-  pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (expr_ False e)+  pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (qualTyName t <> "'" <> parens (expr_ False e)) toSLV (SP _ _) e       = expr_ False e toSLV (CustomSP _ _ _ _) e =   -- Custom representations are represented as bitvectors in HDL, so we don't@@ -2013,48 +1805,11 @@ toSLV (Vector _ _) e = do   nm <- Mon $ use modNm   pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (expr_ False e)+toSLV (RTree _ _) e = do+  nm <- Mon (use modNm)+  pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (expr_ False e) toSLV hty e = error $ $(curLoc) ++  "toSLV:\n\nType: " ++ show hty ++ "\n\nExpression: " ++ show e -fromSLV :: HasCallStack => HWType -> Identifier -> Int -> Int -> VHDLM Doc-fromSLV Bool              id_ start _   = do-  nm <- Mon $ use modNm-  pretty (TextS.toLower nm) <> "_types.fromSLV" <> parens (pretty id_ <> parens (int start <+> "downto" <+> int start))-fromSLV Bit                 id_ start _   = pretty id_ <> parens (int start)-fromSLV (BitVector _)       id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV (Index _)           id_ start end = "unsigned" <> parens (pretty id_ <> parens (int start <+> "downto" <+> int end))-fromSLV (Signed _)          id_ start end = "signed" <> parens (pretty id_ <> parens (int start <+> "downto" <+> int end))-fromSLV (Unsigned _)        id_ start end = "unsigned" <> parens (pretty id_ <> parens (int start <+> "downto" <+> int end))-fromSLV (Sum _ _)           id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV (CustomSum _ _ _ _) id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV t@(Product _ labels tys) id_ start _ = do-    tupled $ zipWithM (\s e -> s <+> rarrow <+> e) selNames args-  where-    tName      = tyName t-    selNames   = [tName <> selectProductField labels tys i | i <- [0..]]-    argLengths = map typeSize tys-    starts     = start : snd (mapAccumL ((join (,) .) . (-)) start argLengths)-    ends       = map (+1) (tail starts)-    args       = zipWith3 (`fromSLV` id_) tys starts ends--fromSLV (CustomSP _ _ _ _)  id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV (CustomProduct {})  id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV (SP _ _)            id_ start end = pretty id_ <> parens (int start <+> "downto" <+> int end)-fromSLV (Vector n elTy)     id_ start _   =-    if n > 1 then tupled args-             else parens (int 0 <+> rarrow <+> fmap head args)-  where-    argLength = typeSize elTy-    starts    = take (n + 1) $ iterate (subtract argLength) start-    ends      = map (+1) (tail starts)-    args      = do syn <- Mon hdlSyn-                   let elTy' = case syn of-                                 Vivado -> BitVector (argLength - 1)-                                 _ -> elTy-                   zipWithM (fromSLV elTy' id_) starts ends-fromSLV (Clock {})        id_ start _   = pretty id_ <> parens (int start)-fromSLV (Reset {})        id_ start _   = pretty id_ <> parens (int start)-fromSLV hty               _   _     _   = error $ $(curLoc) ++ "fromSLV: " ++ show hty- dcToExpr :: HWType -> Int -> Expr dcToExpr ty i = Literal (Just (ty,conSize ty)) (NumLit (toInteger i)) @@ -2080,3 +1835,358 @@ tupledSemi = align . encloseSep (flatAlt (lparen <+> emptyDoc) lparen)                                 (flatAlt (emptyDoc <+> rparen) rparen)                                 (semi <+> emptyDoc)++-- | VHDL name modifiers+data VHDLModifier+  -- | SLV slice (descending index)+  = Range    Range+  -- | Element selection+  | Idx      Int+  -- | Array slice (ascending index)+  | Slice    Int Int+  -- | Selected names+  | Select   (VHDLM Doc)+  -- | Projecting a 'Word#' out of a 'Word8', or 'Int#' ouf of an 'Int8', see+  -- [Note] integer projection+  | Resize+  -- | Projecting a 'Natural' out of a 'BitVector', see [Note] bitvector projection+  | ResizeAndConvert+  -- | Projecting the mask out of a 'BitVector', see [Note] mask projection+  | DontCare++-- | Create a sequence of VHDL name modifiers from our internal 'Modifier'+-- data type. Note that the modifiers are in "reverse" order, so build a+-- complete modified name using 'foldr' over the list by this function.+--+-- [Note] Continuing from an SLV slice+-- SOP and custom products are represented as std_logic_vector, this means that+-- their elements are also std_logic_vector. So when we project an element out+-- of an SOP or custom project, and want to do a further projection on that,+-- we have to do further SLV slicing; instead of e.g. creating a 'selected'+-- modifier. Finally, when we render the modified name, we have to check+-- whether the ultimately projected type needs to be converted from this SLV+-- slice, to the proper type.+buildModifier+  :: HasCallStack+  => HdlSyn+  -> [(VHDLModifier,HWType)]+  -- ^ The list of modifiers so far, note that this list is in reverse order+  -- in which they should eventually be applied to the name we want to modify+  -> Modifier+  -> Maybe [(VHDLModifier,HWType)]+  -- ^ 'Nothing' indicates that the 'Modifier' does not result into a VHDL name+  -- modifier. i.e. we can use the identifier as is; this happens when we get+  -- projections out of product types with only one non-zero field.+buildModifier _ prevM (Sliced (_,start,end)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      Just (first Range (continueWithRange [(start,end)] hty r) : rest)+  _ ->+      Just ((Range (Contiguous start end),hty) : prevM)+ where+  hty = BitVector (start-end+1)++buildModifier _ prevM (Indexed (ty@(SP _ args),dcI,fI)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      Just (first Range (continueWithRange [(start,end)] argTy r) : rest)+  _ ->+      Just ((Range (Contiguous start end),argTy) : prevM)+ where+  argTys   = snd (indexNote "SOP type: invalid constructor index" args dcI)+  argTy    = indexNote "SOP type: invalid field index" argTys fI+  argSize  = typeSize argTy+  other    = otherSize argTys (fI-1)+  start    = typeSize ty - 1 - conSize ty - other+  end      = start - argSize + 1++buildModifier _ prevM (Indexed (ty@(Product _ labels tys),_,fI)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let argSize = typeSize argTy+          otherSz = otherSize tys (fI - 1)+          start   = typeSize ty - 1 - otherSz+          end     = start - argSize + 1+      in  Just (first Range (continueWithRange [(start,end)] argTy r) : rest)+  _ ->+      let d = dot <> tyName ty <> selectProductField labels tys fI+      in  Just ((Select d,argTy):prevM)+ where+  argTy = indexNote "Product type: invalid field index" tys fI++buildModifier syn prevM (Indexed (ty@(Vector _ argTy),1,0)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let argSize = typeSize argTy+          start   = typeSize ty - 1+          end     = start - argSize + 1+      in  Just (first Range (continueWithRange [(start,end)] argTy r) : rest)+    | (Slice start _,Vector _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we just pick its first element+      Just (vivadoRange syn argTy ((Idx start,argTy):rest))+  _ ->+      Just (vivadoRange syn argTy ((Idx 0,argTy):prevM))++buildModifier _ prevM (Indexed (ty@(Vector n argTy),1,1)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let argSize = typeSize argTy+          start   = typeSize ty - argSize - 1+      in  Just (first Range (continueWithRange [(start,0)] tyN r) : rest)+    | (Slice start end,Vector _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we just pick the tail of that slice+      Just ((Slice (start + 1) end,tyN) : rest)+  _ ->+      Just ((Slice 1 (n-1),tyN) : prevM)+ where+  tyN = Vector (n-1) argTy++buildModifier syn prevM (Indexed (ty@(RTree _ argTy),0,0)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let start = typeSize ty - 1+      in  Just (first Range (continueWithRange [(start,0)] argTy r) : rest)+    | (Slice start _,RTree _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we just pick its first element+      Just (vivadoRange syn argTy ((Idx start,argTy):rest))+  _ ->+      Just (vivadoRange syn argTy ((Idx 0,argTy):prevM))++buildModifier _ prevM (Indexed (ty@(RTree d argTy),1,0)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let start = typeSize ty - 1+          end   = typeSize ty `div` 2+      in  Just (first Range (continueWithRange [(start,end)] tyN r) : rest)+    | (Slice start _,RTree _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we just pick the left half+      Just ((Slice start (start+z-1),tyN) : rest)+  _ ->+      Just ((Slice 0 (z-1),tyN) : prevM)+ where+  tyN = RTree (d-1) argTy+  z   = 2^(d - 1)++buildModifier _ prevM (Indexed (ty@(RTree d argTy),1,1)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let start = typeSize ty `div` 2 - 1+      in  Just (first Range (continueWithRange [(start,0)] tyN r) : rest)+    | (Slice _ end,RTree _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we just pick the right half+      Just ((Slice (end - z + 1) end,tyN) : rest)+  _ ->+      Just ((Slice z (z'-1),tyN) : prevM)+ where+  tyN = RTree (d-1) argTy+  z   = 2^(d - 1)+  z'  = 2^d++-- This is a HACK for Clash.Driver.TopWrapper.mkOutput+-- Vector's don't have a 10'th constructor, this is just so that we can+-- recognize the particular case+buildModifier syn prevM (Indexed (ty@(Vector _ argTy),10,fI)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let argSize = typeSize argTy+          start   = typeSize ty - (fI * argSize) - 1+          end     = start - argSize + 1+      in  Just (first Range (continueWithRange [(start,end)] argTy r) : rest)+    | (Slice start _,Vector _ argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we offset from its starting element+      Just (vivadoRange syn argTy ((Idx (start+fI),argTy):rest))+  _ ->+      Just (vivadoRange syn argTy (((Idx fI,argTy):prevM)))++-- This is a HACK for Clash.Driver.TopWrapper.mkOutput+-- RTree's don't have a 10'th constructor, this is just so that we can+-- recognize the particular case+buildModifier syn prevM (Indexed (ty@(RTree _ argTy),10,fI)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      let argSize = typeSize argTy+          start   = typeSize ty - (fI * argSize) - 1+          end     = start - argSize + 1+      in  Just (first Range (continueWithRange [(start,end)] argTy r) : rest)+    | (Slice start _,RTree 1 argTyP) <- prev+    , argTy == argTyP ->+      -- If the last modifier was an array slice, we offset from its starting element+      Just (vivadoRange syn argTy ((Idx (start+fI),argTy):rest))+  _ ->+      Just (vivadoRange syn argTy ((Idx fI,argTy):prevM))++buildModifier _ prevM (Indexed (CustomSP _ dataRepr size args,dcI,fI))+  | Void {} <- argTy+  = error (unexpectedProjectionErrorMsg dataRepr dcI fI)+  | otherwise+  = case prevM of+    (prev:rest)+      | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+        Just (first Range (continueWithRange ses argTy r) : rest)+    _ ->+        Just (first Range (continueWithRange ses argTy (Contiguous (size-1) 0)) : prevM)+ where+  (ConstrRepr' _name _n _mask _value anns, _, argTys) =+    indexNote "Custom SOP type: invalid constructor index" args dcI+  ses = bitRanges (indexNote "Custom SOP type: invalid annotation index" anns fI)+  argTy = indexNote "Custom SOP type: invalid field index" argTys fI++buildModifier _ prevM (Indexed (CustomProduct _ dataRepr size _ args,dcI,fI))+  | Void {} <- argTy+  = error (unexpectedProjectionErrorMsg dataRepr dcI fI)+  | DataRepr' _typ _size [cRepr] <- dataRepr+  , ConstrRepr' _cName _pos _mask _val fieldAnns <- cRepr+  , let ses = bitRanges (indexNote "Custom product type: invalid annotation index"+                         fieldAnns fI)+  = case prevM of+      (prev:rest)+        | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+          Just (first Range (continueWithRange ses argTy r) : rest)+      _ ->+          Just (first Range (continueWithRange ses argTy (Contiguous (size-1) 0)):prevM)+ where+  argTy = snd (indexNote "Custom product type: invalid field index" args fI)++buildModifier _ prevM (DC (ty@(SP _ _),_)) = case prevM of+  (prev:rest)+    | (Range r,_) <- prev -> -- See [Note] Continuing from an SLV slice+      Just (first Range (continueWithRange [(start,end)] tyN r) : rest)+  _ ->+      Just ((Range (Contiguous start end),tyN):prevM)+ where+  start = typeSize ty - 1+  end   = typeSize ty - conSize ty+  tyN   = BitVector (start - end + 1)++buildModifier syn prevM (Nested m1 m2) = case buildModifier syn prevM m1 of+  Nothing -> buildModifier syn prevM m2+  Just prevM1 -> case buildModifier syn prevM1 m2 of+      -- In case the second modifier is `Nothing` that means we want the entire+      -- thing calculated by the first modifier+      Nothing -> Just prevM1+      m       -> m++-- [Note] integer projection+--+-- The idea behind these expressions is to translate cases like:+--+-- > :: Int8 -> Int#+-- > \case I8# i -> i+--+-- Which is fine, because no bits are lost. However, these expression might+-- also be the result of the W/W transformation (or uses of unsafeToInteger)+-- for:+--+-- > :: Signed 128 -> Integer+-- > \case S i -> i+--+-- which is very bad because `Integer` is represented by 64 bits meaning we+-- we lose the top 64 bits in the above translation.+--+-- Just as bad is that+--+-- > :: Word8 -> Word#+-- > \case W8# w -> w+--+-- > :: Unsigned 8 -> Integer+-- > \case U i -> i+--+-- result in the same expression... even though their resulting types are+-- different. TODO: this needs  to be fixed!+buildModifier _ prevM (Indexed (ty@(Signed _),_,_)) = Just ((Resize,ty):prevM)+buildModifier _ prevM (Indexed (ty@(Unsigned _),_,_)) = Just ((Resize,ty):prevM)++-- [Note] mask projection+--+-- This covers the case of either:+--+-- `Clash.Sized.Internal.BitVector.unsafeToMask` or+--+-- > :: BitVector 8 -> Integer+-- > \case BV m wild -> m+--+-- introduced by the W/W transformation. Both of which we prefer not to see+-- but will allow. Since the mask is pretty much a simulation artifact we+-- emit don't cares so stuff gets optimised away.+buildModifier _ prevM (Indexed (ty@(BitVector _),_,0)) = Just ((DontCare,ty):prevM)++-- [Note] bitvector projection+--+-- This covers the case of either:+--+-- `Clash.Sized.Internal.BitVector.unsafeToNatural` or+--+-- > :: BitVector 8 -> Integer+-- > \case BV wild i -> i+--+-- introduced by the W/W transformation. Both of which we prefer not to see+-- but will allow.+buildModifier _ prevM (Indexed (ty@(BitVector _),_,1)) = Just ((ResizeAndConvert,ty):prevM)++buildModifier _ _ _ = Nothing++-- | Add an SLV slice for the entire element when we're in the Vivado code-path.+-- This is needed after an element projection from an array (Vec or RTree), as+-- elements are stored as SLVs in the Vivado code-path. This enabled two things:+--+-- 1. Nested modifiers treat the projected element as an SLV, and adjust their+--    projection behavior accordingly.+-- 2. Projected elements are converted from SLV to the proper VHDL type.+vivadoRange+  :: HdlSyn+  -> HWType+  -> [(VHDLModifier, HWType)]+  -> [(VHDLModifier, HWType)]+vivadoRange syn ty mods = case syn of+  Vivado -> (Range (Contiguous (typeSize ty - 1) 0),ty):mods+  _ -> mods++-- | Render a VHDL modifier on to of a (potentially modified) VHDL name+renderModifier+  :: (VHDLModifier,HWType)+  -> VHDLM Doc+  -- ^ (Potentially modified) VHDL name+  -> VHDLM Doc+  -- ^ Modified VHDL name+renderModifier (Idx n,_) doc = doc <> parens (int n)+renderModifier (Slice start end,_) doc = doc <> parens (int start <+> "to" <+> int end)+renderModifier (Select sel,_) doc = doc <> sel+-- See [Note] integer projection+renderModifier (Resize,ty) doc = do+  iw <- Mon (use intWidth)+  -- These integer projections always come last, so it's safe not to return a+  -- modified name, but an expression instead.+  traceIf (iw < typeSize ty) ($(curLoc) ++ "WARNING: result smaller than argument") $+    "resize" <> parens (doc <> "," <> int iw)+renderModifier (ResizeAndConvert,ty) doc = do+  iw <- Mon (use intWidth)+  -- These natural projections always come last, so it's safe not to return a+  -- modified name, but an expression instead.+  traceIf (iw < typeSize ty) ($(curLoc) ++ "WARNING: result smaller than argument") $+    "resize" <> parens ("unsigned" <> parens doc <> "," <> int iw)+-- See [Note] mask projection+renderModifier (DontCare,_) _ = do+  iw <- Mon (use intWidth)+  -- These mask projections always come last, so it's safe not to return a+  -- modified name, but an expression instead.+  traceIf True ($(curLoc) ++ "WARNING: rendering bitvector mask as dontcare") $+    sizedQualTyNameErrValue (Signed iw)+renderModifier (Range r,t) doc = do+  nm <- Mon (use modNm)+  let doc1 = case r of+        Contiguous start end -> slice start end+        Split rs -> parens (hcat (punctuate " & " (mapM (\(s,e,_) -> slice s e) rs)))+  case normaliseType t of+    BitVector _ -> doc1+    -- See [Note] Continuing from an SLV slice+    _ ->+      qualTyName t <> "'" <>+      parens (pretty (TextS.toLower nm) <> "_types.fromSLV" <> parens doc1)+ where+  slice s e = doc <> parens (int s <+> "downto" <+> int e)
src/Clash/Backend/Verilog.hs view
@@ -24,6 +24,9 @@   , bits   , bit_char   , noEmptyInit+  -- * split ranges+  , Range (..)+  , continueWithRange   ) where @@ -34,13 +37,16 @@ import           Data.Bits                            (Bits, testBit) import           Data.HashMap.Strict                  (HashMap) import qualified Data.HashMap.Strict                  as HashMap+import           Data.HashSet                         (HashSet) import qualified Data.HashSet                         as HashSet import           Data.Maybe                           (catMaybes,fromMaybe,mapMaybe)-import           Data.List                            (nub, nubBy)+import           Data.List+  (mapAccumL, mapAccumR, nubBy, foldl')+import           Data.List.Extra                      ((<:>)) #if !MIN_VERSION_base(4,11,0) import           Data.Monoid                          hiding (Product, Sum) #endif-import           Data.Semigroup.Monad+import           Data.Semigroup.Monad.Extra import           Data.Text.Lazy                       (pack) import qualified Data.Text.Lazy                       as Text import qualified Data.Text                            as TextS@@ -49,15 +55,15 @@ import           GHC.Stack                            (HasCallStack)  import           Clash.Annotations.Primitive          (HDL (..))-import           Clash.Annotations.BitRepresentation  (BitMask) import           Clash.Annotations.BitRepresentation.ClashLib   (bitsToBits) import           Clash.Annotations.BitRepresentation.Internal   (ConstrRepr'(..), DataRepr'(..), ConstrRepr'(..)) import           Clash.Annotations.BitRepresentation.Util-  (BitOrigin(Lit, Field), bitOrigins, bitRanges, isContinuousMask)+  (BitOrigin(Lit, Field), bitOrigins, bitRanges) import           Clash.Core.Var                       (Attr'(..)) import           Clash.Backend+import           Clash.Debug                          (traceIf) import           Clash.Netlist.BlackBox.Types         (HdlSyn) import           Clash.Netlist.BlackBox.Util   (extractLiterals, renderBlackBox, renderFilePath)@@ -66,8 +72,7 @@ import           Clash.Netlist.Util                   hiding (mkIdentifier, extendIdentifier) import           Clash.Signal.Internal                (ActiveEdge (..)) import           Clash.Util-  (SrcSpan, noSrcSpan, curLoc, traceIf, (<:>), on, first, indexNote)-+  (SrcSpan, noSrcSpan, curLoc, on, first, indexNote, makeCached, second)  -- | State for the 'Clash.Backend.Verilog.VerilogM' monad: data VerilogState =@@ -76,13 +81,15 @@     , _idSeen    :: HashMap Identifier Word     , _srcSpan   :: SrcSpan     , _includes  :: [(String,Doc)]-    , _imports   :: [Text.Text]-    , _libraries :: [Text.Text]+    , _imports   :: HashSet Text.Text+    , _libraries :: HashSet Text.Text     , _dataFiles      :: [(String,FilePath)]     -- ^ Files to be copied: (filename, old path)     , _memoryDataFiles:: [(String,String)]     -- ^ Files to be stored: (filename, contents). These files are generated     -- during the execution of 'genNetlist'.+    , _customConstrs :: HashMap Identifier Identifier+    -- ^ Custom data constructor => Verilog function name     , _intWidth  :: Int -- ^ Int/Word/Integer bit-width     , _hdlsyn    :: HdlSyn     , _escapedIds :: Bool@@ -92,7 +99,16 @@ makeLenses ''VerilogState  instance Backend VerilogState where-  initBackend     = VerilogState 0 HashMap.empty noSrcSpan [] [] [] [] []+  initBackend     = VerilogState+                      0+                      HashMap.empty+                      noSrcSpan+                      []+                      HashSet.empty+                      HashSet.empty+                      []+                      []+                      HashMap.empty   hdlKind         = const Verilog   primDirs        = const $ do root <- primsRoot                                return [ root System.FilePath.</> "common"@@ -163,9 +179,9 @@         pure decs <> line <>         insts ds   unextend = return rmSlash-  addIncludes inc = includes %= (inc++)-  addLibraries libs = libraries %= (libs ++)-  addImports inps = imports %= (inps ++)+  addIncludes inc = includes %= (inc ++)+  addLibraries libs = libraries %= (\s -> foldl' (flip HashSet.insert) s libs)+  addImports inps = imports %= (\s -> foldl' (flip HashSet.insert) s inps)   addAndSetData f = do     fs <- use dataFiles     let (fs',f') = renderFilePath fs f@@ -241,13 +257,17 @@     iE = maybe emptyDoc (noEmptyInit . expr_ False) iEM  module_ :: Component -> VerilogM Doc-module_ c = addSeen c *> modVerilog <* Mon (imports .= [])+module_ c =+  addSeen c *> modVerilog <* Mon (imports .= HashSet.empty >> libraries .= HashSet.empty)   where     modVerilog = do       body <- modBody       imps <- Mon $ use imports       libs <- Mon $ use libraries-      modHeader <> line <> modPorts <> line <> include (nub imps) <> uselibs (nub libs) <> pure body <> line <> modEnding+      modHeader <> line <> modPorts <> line <>+        include (HashSet.toList imps) <>+        uselibs (HashSet.toList libs) <>+        pure body <> line <> modEnding      modHeader  = "module" <+> stringS (componentName c)     modPorts   = indent 4 (tupleInputs inPorts <> line <> tupleOutputs outPorts <> semi)@@ -331,8 +351,8 @@   :: HWType   -> Int   -> VerilogM Doc-verilogRecSel ty i = case modifier 0 (Indexed (ty,0,i)) of-  Just (start,end,_resTy) -> brackets (int start <> colon <> int end)+verilogRecSel ty i = case modifier (Contiguous 0 0) (Indexed (ty,0,i)) of+  Just (Contiguous start end,_resTy) -> brackets (int start <> colon <> int end)   _ -> error "Can't make a record selector"  decls :: [Declaration] -> VerilogM Doc@@ -579,18 +599,166 @@ seqs (SeqDecl (TickDecl id_):ds) = "//" <+> stringS id_ <> line <> seqs ds seqs (d:ds) = seq_ d <> line <> line <> seqs ds +-- | Range slice, can be contiguous, or split into multiple sub-ranges+data Range+  = Contiguous Int Int+  | Split [(Int,Int,Provenance)]++-- | Original index range of a split range element+data Provenance+  = Provenance Int Int++-- | Slice ranges out of a split-range element+inRange+  :: [(Int,Int)]+  -- ^ start and end indexes into the original data type+  -> (Int,Int,Provenance)+  -- ^ Element of a split range+  -> ([(Int,Int)],[(Int,Int,Provenance)])+  -- ^+  -- 1. stand and end indexes to be sliced from the rest of the split range elements+  -- 2. Subset of the current split range for the projected data type+inRange [] _ = ([],[])+inRange ((start,end):ses) orig@(_,endRange,Provenance _ endProvenance) =+{-+The following explains the index calculations++== Start ==+-----------------------------------+|     2     | |    1   | |   0    |  <- split range element number+|15|14|13|12| |10| 9| 8| | 4| 3| 2|  <- split range indexes+-----------------------------------+| 9| 8| 7| 6| | 5| 4| 3| | 2| 1| 0|  <- original indexes of the data type (provenance)+-----------------------------------+                   4          1      <- `start` and `end` index that we want to slice++== split range element 2 ==+startOffset: start(4) - endProvenance(6) = -2++next start: 4+next end:   1++== split range element 1 ==+startOffset: start(4) - endProvenance(3) = 1+endOffSet  : end(1) - endProvenance(3) = -2++startRangeNew: endRange(8) + startOffSet(1) = 9+endRangeNew  : endRange(8)++startProvenanceNew: start(4) - end(1)                    = 3+endProvenanceNew  : startProvenanceNew(3)-startOffset(1) = 2++newSplitRange:+-------+|  1  |+| 9| 8| <- new split range element+-------+| 3| 2| <- index into the projected data type++next start: endProvenance(3) - 1 = 2+next end  : 1++== split range element 0 ==+startOffset: start(2) - endProvenance(0) = 2+endOffset  : end(1) - endProvenance(0)   = 1++startRangeNew: endRange(2) + startOffSet(2) = 4+endRangeNew  : endRange(2) + endOffSet(1)   = 3++startProvenanceNew: start(2) - end(1) = 1+endProvenanceNew  :                   = 0++newSplitRange:+-------+|  0  |+| 4| 3| <- new split range element+-------+| 1| 0| <- index into the projected data type+-}+  let startOffset = start - endProvenance+      endOffset   = end   - endProvenance+  in+  if startOffset >= 0 then+    let startRangeNew = endRange + startOffset+        endRangeNew =+          if endOffset >= 0 then+             endRange + endOffset+          else+            endRange++        startProvenanceNew = start - end+        endProvenanceNew =+          if endOffset >= 0 then+            0+          else+            startProvenanceNew - startOffset++        newSplitRange =+          ( startRangeNew+          , endRangeNew+          , Provenance startProvenanceNew endProvenanceNew)+    in+    if endOffset >= 0 then+      -- try to slice the next start+end in the current split range element+      second (newSplitRange:) (inRange ses orig)+    else+      -- continue the slice in the next split range element+      ((endProvenance-1,end):ses,[newSplitRange])+  else+    -- start offset beyond last bit in the element of the split range+    ((start,end):ses,[])++-- | Create an Split range element+buildSplitRange+  :: Int+  -- ^ Offset+  -> Int+  -- ^ End index into the original data type+  -> (Int,Int)+  -- ^ start and end index for this sub-range+  -> (Int,(Int,Int,Provenance))+buildSplitRange offset eP (s,e) =+  let d = s-e in+  (eP+d+1,(s + offset, e + offset, Provenance (eP+d) eP))++-- | Select a sub-range from a range+continueWithRange+  :: [(Int,Int)]+  -- ^ Starts and ends+  -> HWType+  -- ^ Type of the projection+  -> Range+  -- ^ Range selected so far+  -> (Range, HWType)+continueWithRange ses hty r = case r of+  Contiguous _ offset -> case ses of+    [(start,end)] ->+      (Contiguous (start+offset) (end+offset), hty)+    ses1 ->+      let ses2 = snd (mapAccumR (buildSplitRange offset) 0 ses1) in+      (Split ses2, hty)+  Split rs -> case concat (snd (mapAccumL inRange ses rs)) of+    [] -> error "internal error"+    [(s1,e1,_)] -> (Contiguous s1 e1,hty)+    rs1 -> (Split rs1,hty)+ -- | Calculate the beginning and end index into a variable, to get the -- desired field. -- Also returns the HWType of the result. modifier   :: HasCallStack-  => Int-  -- ^ Offset, only used when we have nested modifiers+  => Range+  -- ^ Range selected so far   -> Modifier-  -> Maybe (Int,Int,HWType)-modifier offset (Sliced (BitVector _,start,end)) = Just (start+offset,end+offset, BitVector (start-end+1))+  -> Maybe (Range,HWType)+modifier r (Sliced (BitVector _,start,end)) =+  Just (continueWithRange [(start,end)] hty r)+  where+    hty = BitVector (start-end-1) -modifier offset (Indexed (ty@(SP _ args),dcI,fI)) = Just (start+offset,end+offset, argTy)++modifier r (Indexed (ty@(SP _ args),dcI,fI)) =+  Just (continueWithRange [(start,end)] argTy r)   where     argTys   = snd $ args !! dcI     argTy    = argTys !! fI@@ -599,7 +767,8 @@     start    = typeSize ty - 1 - conSize ty - other     end      = start - argSize + 1 -modifier offset (Indexed (ty@(Product _ _ argTys),_,fI)) = Just (start+offset,end+offset, argTy)+modifier r (Indexed (ty@(Product _ _ argTys),_,fI)) =+  Just (continueWithRange [(start,end)] argTy r)   where     argTy   = argTys !! fI     argSize = typeSize argTy@@ -607,34 +776,43 @@     start   = typeSize ty - 1 - otherSz     end     = start - argSize + 1 -modifier offset (Indexed (ty@(Vector _ argTy),1,0)) = Just (start+offset,end+offset, argTy)+modifier r (Indexed (ty@(Vector _ argTy),1,0)) =+  Just (continueWithRange [(start,end)] argTy r)   where     argSize = typeSize argTy     start   = typeSize ty - 1     end     = start - argSize + 1 -modifier offset (Indexed (ty@(Vector n argTy),1,1)) = Just (start+offset,offset,Vector (n-1) argTy)+modifier r (Indexed (ty@(Vector n argTy),1,1)) =+  Just (continueWithRange [(start,0)] hty r)   where     argSize = typeSize argTy     start   = typeSize ty - argSize - 1+    hty     = Vector (n-1) argTy -modifier offset (Indexed (ty@(RTree 0 argTy),0,0)) = Just (start+offset,offset, argTy)+modifier r (Indexed (ty@(RTree 0 argTy),0,0)) =+  Just (continueWithRange [(start,0)] argTy r)   where     start   = typeSize ty - 1 -modifier offset (Indexed (ty@(RTree d argTy),1,0)) = Just (start+offset,end+offset,RTree (d-1) argTy)+modifier r (Indexed (ty@(RTree d argTy),1,0)) =+  Just (continueWithRange [(start,end)] hty r)   where     start   = typeSize ty - 1     end     = typeSize ty `div` 2+    hty     = RTree (d-1) argTy -modifier offset (Indexed (ty@(RTree d argTy),1,1)) = Just (start+offset,offset, RTree (d-1) argTy)+modifier r (Indexed (ty@(RTree d argTy),1,1)) =+  Just (continueWithRange [(start,0)] hty r)   where     start   = (typeSize ty `div` 2) - 1+    hty     = RTree (d-1) argTy  -- This is a HACK for Clash.Driver.TopWrapper.mkOutput -- Vector's don't have a 10'th constructor, this is just so that we can -- recognize the particular case-modifier offset (Indexed (ty@(Vector _ argTy),10,fI)) = Just (start+offset,end+offset, argTy)+modifier r (Indexed (ty@(Vector _ argTy),10,fI)) =+  Just (continueWithRange [(start,end)] argTy r)   where     argSize = typeSize argTy     start   = typeSize ty - (fI * argSize) - 1@@ -643,51 +821,40 @@ -- This is a HACK for Clash.Driver.TopWrapper.mkOutput -- RTree's don't have a 10'th constructor, this is just so that we can -- recognize the particular case-modifier offset (Indexed (ty@(RTree _ argTy),10,fI)) = Just (start+offset,end+offset, argTy)+modifier r (Indexed (ty@(RTree _ argTy),10,fI)) =+  Just (continueWithRange [(start,end)] argTy r)   where     argSize = typeSize argTy     start   = typeSize ty - (fI * argSize) - 1     end     = start - argSize + 1 -modifier offset (Indexed (CustomSP typName _dataRepr _size args,dcI,fI)) =-  case bitRanges (anns !! fI) of-    [(start,end)] ->-      Just (start+offset,end+offset, argTy)-    _ ->-      error $ $(curLoc) ++ "Cannot handle projection out of a "-           ++ "non-contiguously or zero-width encoded field. Tried to project "-           ++ "field " ++ show fI ++ " of constructor " ++ show dcI ++ " of "-           ++ "data type " ++ show typName ++  "."- where-  (ConstrRepr' _name _n _mask _value anns, _, argTys) = args !! dcI-  argTy = argTys !! fI+modifier r (Indexed (CustomSP _typName _dataRepr _size args,dcI,fI)) =+  Just (continueWithRange ses argTy r)+  where+    ses = bitRanges (anns !! fI)+    (ConstrRepr' _name _n _mask _value anns, _, argTys) = args !! dcI+    argTy = argTys !! fI -modifier offset (Indexed (CustomProduct typName dataRepr _size _maybeFieldNames args,dcI,fI))+modifier r (Indexed (CustomProduct _typName dataRepr _size _maybeFieldNames args,_,fI))   | DataRepr' _typ _size [cRepr] <- dataRepr-  , ConstrRepr' _cName _pos _mask _val fieldAnns <- cRepr =-  case bitRanges (fieldAnns !! fI) of-    [(start,end)] ->-      Just (start+offset,end+offset, argTy)-    _ ->-      error $ $(curLoc) ++ "Cannot handle projection out of a "-           ++ "non-contiguously or zero-width encoded field. Tried to project "-           ++ "field " ++ show fI ++ " of constructor " ++ show dcI ++ " of "-           ++ "data type " ++ show typName ++ "."+  , ConstrRepr' _cName _pos _mask _val fieldAnns <- cRepr+  = let ses = bitRanges (fieldAnns !! fI) in Just (continueWithRange ses argTy r)  where   argTy = map snd args !! fI -modifier offset (DC (ty@(SP _ _),_)) = Just (start+offset,end+offset, ty)+modifier r (DC (ty@(SP _ _),_)) =+  Just (continueWithRange [(start,end)] ty r)   where     start = typeSize ty - 1     end   = typeSize ty - conSize ty -modifier offset (Nested m1 m2) = do-  case modifier offset m1 of-    Nothing    -> modifier offset m2-    Just (s,e,argTy) -> case modifier e m2 of+modifier r (Nested m1 m2) = do+  case modifier r m1 of+    Nothing -> modifier r m2+    Just (r1,argTy) -> case modifier r1 m2 of       -- In case the second modifier is `Nothing` that means we want the entire       -- thing calculated by the first modifier-      Nothing -> Just (s,e,argTy)+      Nothing -> Just (r1,argTy)       m       -> m  modifier _ _ = Nothing@@ -702,45 +869,67 @@   -> [(HWType, Expr)]   -- ^ Arguments applied to constructor   -> VerilogM Doc-customReprDataCon dataRepr constrRepr args =-  (flip fromMaybe) (errOnNonContinuous 0 anns) $-  braces $ hcat $ punctuate ", " $ mapM range' origins-    where-      anns = crFieldAnns constrRepr-      size = drSize dataRepr+customReprDataCon dataRepr constrRepr [] =+  let origins = bitOrigins dataRepr constrRepr :: [BitOrigin] in+  case origins of+    [Lit (bitsToBits -> ns)] ->+      int (length ns) <> squote <> "b" <> hcat (mapM (bit_char undefValue) ns)+    _ -> error "internal error"+customReprDataCon dataRepr constrRepr args = do+  funId <- mkConstrFunction+  Mon (imports %= HashSet.insert (Text.pack (TextS.unpack funId ++ ".inc")))+  stringS funId <> tupled (mapM (expr_ False . snd) nzArgs)+ where+  nzArgs = filter ((/=0) . typeSize . fst) args -      errOnNonContinuous :: Int -> [BitMask] -> Maybe a-      errOnNonContinuous _ [] = Nothing-      errOnNonContinuous fieldnr (ann:anns') =-        if isContinuousMask ann then-          errOnNonContinuous (fieldnr + 1) anns'-        else-          error $ $(curLoc) ++ unlines [-              "Error while processing custom bit representation:\n"-            , unwords ["Field", show fieldnr, "of constructor"-            , show (crName constrRepr), "of type\n"]-            , "  " ++ show (drType dataRepr) ++ "\n"-            , "has a non-continuous fieldmask:\n"-            , "  " ++ (map bit_char' $ toBits size ann) ++ "\n"-            , unwords [ "This is not supported in Verilog. Change the mask to a"-                      , "continuous one, or render using VHDL or SystemVerilog."-                      ]-            ]+  mkConstrFunction = makeCached (crName constrRepr) customConstrs $ do+    let size    = drSize dataRepr+        aTys    = map fst args+        origins = bitOrigins dataRepr constrRepr :: [BitOrigin]+    mkId <- Mon mkIdentifier+    let ids = [ mkId Basic (TextS.pack ('v':show n)) | n <- [1..length args] ]+        fId = mkId Basic (crName constrRepr)+    let fInps =+          [ case typeSize t of+              0 -> emptyDoc+              1 -> "input" <+> stringS i <> semi <> line+              n -> "input" <+> brackets (int (n-1) <> colon <> int 0) <+>+                               stringS i <> semi <> line+          | (i,t) <- zip ids aTys+          ] -      -- Build bit representations for all constructor arguments-      argExprs = map (expr_ False) (map snd args) :: [VerilogM Doc]+    let range' (Lit (bitsToBits -> ns)) =+          int (length ns) <> squote <> "b" <> hcat (mapM (bit_char undefValue) ns)+        range' (Field n start end) =+          let v   = ids !! n+              aTy = aTys !! n+          in case typeSize aTy of+               0 -> error "internal error"+               1 -> if start == 0 && end == 0 then+                      stringS v+                    else+                      error "internal error"+               _ -> stringS v <> brackets (int start <> colon <> int end) -      -- Spread bits of constructor arguments using masks-      origins = bitOrigins dataRepr constrRepr :: [BitOrigin]+    let val = case origins of+                []  -> error "internal error"+                [r] -> range' r+                rs  -> listBraces (mapM range' rs) -      range'-        :: BitOrigin-        -> VerilogM Doc-      range' (Lit (bitsToBits -> ns)) =-        int (length ns) <> squote <> "b" <> hcat (mapM (bit_char undefValue) ns)-      range' (Field n _start _end) =-        argExprs !! n+    let oSz = case size of+                0 -> error "internal error"+                1 -> emptyDoc+                n -> brackets (int (n-1) <> colon <> int 0) +    funDoc <-+      "function" <+> oSz <+> stringS fId <> semi <> line <>+      hcat (sequence fInps) <>+      "begin" <> line <>+      indent 2 (stringS fId <+> "=" <+> val <> semi) <> line <>+      "end" <> line <>+      "endfunction"+    Mon (includes %= ((TextS.unpack fId ++ ".inc",funDoc):))+    return fId  -- | Turn a Netlist expression into a Verilog expression expr_ :: Bool -- ^ Enclose in parentheses?@@ -795,11 +984,19 @@   traceIf (iw < w) ($(curLoc) ++ "WARNING: result smaller than argument") $     stringS id_ -expr_ _ (Identifier id_ (Just m)) = case modifier 0 m of+expr_ _ (Identifier id_ (Just m)) = case modifier (Contiguous 0 0) m of   Nothing          -> stringS id_-  Just (start,end,resTy) -> case resTy of-    Signed _ -> "$signed" <> parens (stringS id_ <> brackets (int start <> colon <> int end))-    _        ->                      stringS id_ <> brackets (int start <> colon <> int end)+  Just (Contiguous start end,resTy) -> case resTy of+    Signed _ -> "$signed" <> parens (slice start end)+    _        -> slice start end+  Just (Split rs,resTy) ->+    let rs1 = listBraces (mapM (\(start,end,_) -> slice start end) rs) in+    case resTy of+      Signed _ -> "$signed" <> parens rs1+      _ -> rs1++ where+  slice s e = stringS id_ <> brackets (int s <> colon <> int e)  expr_ b (DataCon _ (DC (Void {}, -1)) [e]) = expr_ b e 
+ src/Clash/Core/EqSolver.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE OverloadedStrings #-}++module Clash.Core.EqSolver where++import Data.Maybe (catMaybes, mapMaybe)++import Clash.Core.Name (Name(nameOcc))+import Clash.Core.Term+import Clash.Core.TyCon+import Clash.Core.Type+import Clash.Core.Var++-- | Data type that indicates what kind of solution (if any) was found+data TypeEqSolution+  = Solution (TyVar, Type)+  -- ^ Solution was found. Variable equals some integer.+  | AbsurdSolution+  -- ^ A solution was found, but it involved negative naturals.+  | NoSolution+  -- ^ Given type wasn't an equation, or it was unsolvable.+    deriving (Show, Eq)++catSolutions :: [TypeEqSolution] -> [(TyVar, Type)]+catSolutions = mapMaybe getSol+ where+  getSol (Solution s) = Just s+  getSol _ = Nothing++-- | Solve given equations and return all non-absurd solutions+solveNonAbsurds :: TyConMap -> [(Type, Type)] -> [(TyVar, Type)]+solveNonAbsurds _tcm [] = []+solveNonAbsurds tcm (eq:eqs) =+  solved ++ solveNonAbsurds tcm eqs+ where+  solvers = [pure . solveAdd, solveEq tcm]+  solved = catSolutions (concat [s eq | s <- solvers])++-- | Solve simple equalities such as:+--+--   * a ~ 3+--   * 3 ~ a+--   * SomeType a b ~ SomeType 3 5+--   * SomeType 3 5 ~ SomeType a b+--   * SomeType a 5 ~ SomeType 3 b+--+solveEq :: TyConMap -> (Type, Type) -> [TypeEqSolution]+solveEq tcm (coreView tcm -> left, coreView tcm -> right) =+  case (left, right) of+    (VarTy tyVar, ConstTy {}) ->+      -- a ~ 3+      [Solution (tyVar, right)]+    (ConstTy {}, VarTy tyVar) ->+      -- 3 ~ a+      [Solution (tyVar, left)]+    (ConstTy {}, ConstTy {}) ->+      -- Int /= Char+      if left /= right then [AbsurdSolution] else []+    (LitTy {}, LitTy {}) ->+      -- 3 /= 5+      if left /= right then [AbsurdSolution] else []+    _ ->+      -- The call to 'coreView' at the start of 'solveEq' should have reduced+      -- all solvable type families. If we encounter one here that means the+      -- type family is stuck (and that we shouldn't compare it to anything!).+      if any (isTypeFamilyApplication tcm) [left, right] then+        []+      else+        case (tyView left, tyView right) of+          (TyConApp leftNm leftTys, TyConApp rightNm rightTys) ->+            -- SomeType a b ~ SomeType 3 5 (or other way around)+            if leftNm == rightNm then+              concat (map (solveEq tcm) (zip leftTys rightTys))+            else+              [AbsurdSolution]+          _ ->+            []++-- | Solve equations supported by @normalizeAdd@. See documentation of+-- @TypeEqSolution@ to understand the return value.+solveAdd+  :: (Type, Type)+  -> TypeEqSolution+solveAdd ab =+  case normalizeAdd ab of+    Just (n, m, VarTy tyVar) ->+      if n >= 0 && m >= 0 && n - m >= 0 then+        Solution (tyVar, (LitTy (NumTy (n - m))))+      else+        AbsurdSolution+    _ ->+      NoSolution++-- | Given the left and right side of an equation, normalize it such that+-- equations of the following forms:+--+--     * 5     ~ n + 2+--     * 5     ~ 2 + n+--     * n + 2 ~ 5+--     * 2 + n ~ 5+--+-- are returned as (5, 2, n)+normalizeAdd+  :: (Type, Type)+  -> Maybe (Integer, Integer, Type)+normalizeAdd (a, b) = do+  (n, rhs) <- lhsLit a b+  case tyView rhs of+    TyConApp (nameOcc -> "GHC.TypeNats.+") [left, right] -> do+      (m, o) <- lhsLit left right+      return (n, m, o)+    _ ->+      Nothing+ where+  lhsLit x                 (LitTy (NumTy n)) = Just (n, x)+  lhsLit (LitTy (NumTy n)) y                 = Just (n, y)+  lhsLit _                 _                 = Nothing++-- | Tests for unreachable alternative due to types being "absurd". See+-- @isAbsurdEq@ for more info.+isAbsurdAlt+  :: TyConMap+  -> Alt+  -> Bool+isAbsurdAlt tcm alt =+  any (isAbsurdEq tcm) (altEqs tcm alt)++-- | Determines if an "equation" obtained through @altEqs@ or @typeEq@ is+-- absurd. That is, it tests if two types that are definitely not equal are+-- asserted to be equal OR if the computation of the types yield some absurd+-- (intermediate) result such as -1.+isAbsurdEq+  :: TyConMap+  -> (Type, Type)+  -> Bool+isAbsurdEq tcm ((left0, right0)) =+  case (coreView tcm left0, coreView tcm right0) of+    (solveAdd -> AbsurdSolution) -> True+    lr -> any (==AbsurdSolution) (solveEq tcm lr)++-- | Get constraint equations+altEqs+  :: TyConMap+  -> Alt+  -> [(Type, Type)]+altEqs tcm (pat, _term) =+ catMaybes (map (typeEq tcm . varType) (snd (patIds pat)))++-- | If type is an equation, return LHS and RHS.+typeEq+  :: TyConMap+  -> Type+  -> Maybe (Type, Type)+typeEq tcm ty =+ case tyView (coreView tcm ty) of+  TyConApp (nameOcc -> "GHC.Prim.~#") [_, _, left, right] ->+    Just (coreView tcm left, coreView tcm right)+  _ ->+    Nothing+
src/Clash/Core/Evaluator.hs view
@@ -26,7 +26,6 @@ import qualified Data.Primitive.ByteArray                as BA import qualified Data.Text as Text import qualified Data.Vector.Primitive                   as PV-import           Debug.Trace import           GHC.Integer.GMP.Internals   (Integer (..), BigNat (..)) @@ -38,11 +37,13 @@ import           Clash.Core.Pretty import           Clash.Core.Subst import           Clash.Core.Term+import           Clash.Core.TermInfo import           Clash.Core.TyCon import           Clash.Core.Type import           Clash.Core.Util import           Clash.Core.Var import           Clash.Core.VarEnv+import           Clash.Debug import           Clash.Driver.Types                      (BindingMap, Binding(..)) import           Clash.Pretty import           Clash.Unique
src/Clash/Core/Pretty.hs view
@@ -32,10 +32,10 @@ import Data.Default                     (Default(..)) import Data.Text                        (Text) import Control.Monad.Identity+import Data.List.Extra                  ((<:>)) import qualified Data.Text              as T import Data.Text.Prettyprint.Doc import Data.Text.Prettyprint.Doc.Internal-import Debug.Trace                      (trace) import GHC.Show                         (showMultiLineString) import Numeric                          (fromRat) import qualified Outputable             as GHC@@ -49,6 +49,7 @@ import Clash.Core.Type                  (ConstTy (..), Kind, LitTy (..),                                          Type (..), TypeView (..), tyView) import Clash.Core.Var                   (Id, TyVar, Var (..), IdScope(..))+import Clash.Debug                      (trace) import Clash.Util import Clash.Pretty 
src/Clash/Core/Subst.hs view
@@ -27,6 +27,9 @@   , substTy   , substTyWith   , substTyInVar+  , substGlobalsInExistentials+  , substInExistentials+  , substInExistentialsList     -- * Substitution into terms     -- ** Substitution environments   , Subst (..)@@ -55,6 +58,7 @@ import           Data.Coerce               (coerce) import           Data.Text.Prettyprint.Doc import qualified Data.List                 as List+import qualified Data.List.Extra           as List import           Data.Ord                  (comparing)  import           Clash.Core.FreeVars@@ -65,6 +69,7 @@ import           Clash.Core.Type           (Type (..)) import           Clash.Core.VarEnv import           Clash.Core.Var            (Id, Var (..), TyVar, isGlobalId)+import           Clash.Debug               (debugIsOn) import           Clash.Unique import           Clash.Util import           Clash.Pretty@@ -239,7 +244,7 @@   -> Subst zipTvSubst tvs tys   | debugIsOn-  , neLength tvs tys+  , not (List.equalLength tvs tys)   = pprTrace "zipTvSubst" (ppr tvs <> line <> ppr tys) emptySubst   | otherwise   = Subst (mkInScopeSet (tyFVsOfTypes tys)) emptyVarEnv tenv emptyVarEnv@@ -250,7 +255,7 @@   :: [TyVar]   -> [Type]   -> VarEnv Type-zipTyEnv tvs tys = mkVarEnv (zipEqual tvs tys)+zipTyEnv tvs tys = mkVarEnv (List.zipEqual tvs tys)  -- | Extend the substitution environment with a new 'Id' substitution extendIdSubst@@ -357,6 +362,63 @@   | otherwise   = substTy' subst ty +-- Safely substitute global type variables in a list of potentially+-- shadowing type variables.+substGlobalsInExistentials+  :: HasCallStack+  => InScopeSet+  -- ^ Variables in scope+  -> [TyVar]+  -- ^ List of existentials to apply the substitution for+  -> [(TyVar, Type)]+  -- ^ Substitutions+  -> [TyVar]+substGlobalsInExistentials is exts substs0 = result+  -- TODO: Is is actually possible that existentials shadow each other? If they+  -- TODO: can't, we can remove this function+  where+    iss     = scanl extendInScopeSet is exts+    substs1 = map (\is_ -> extendTvSubstList (mkSubst is_) substs0) iss+    result  = zipWith substTyInVar substs1 exts++-- | Safely substitute type variables in a list of existentials. This function+-- will account for cases where existentials shadow each other.+substInExistentialsList+  :: HasCallStack+  => InScopeSet+  -- ^ Variables in scope+  -> [TyVar]+  -- ^ List of existentials to apply the substitution for+  -> [(TyVar, Type)]+  -- ^ Substitutions+  -> [TyVar]+substInExistentialsList is exts substs =+  foldl (substInExistentials is) exts substs++-- | Safely substitute a type variable in a list of existentials. This function+-- will account for cases where existentials shadow each other.+substInExistentials+  :: HasCallStack+  => InScopeSet+  -- ^ Variables in scope+  -> [TyVar]+  -- ^ List of existentials to apply the substitution for+  -> (TyVar, Type)+  -- ^ Substitution+  -> [TyVar]+substInExistentials is exts subst@(typeVar, _type) =+  -- TODO: Is is actually possible that existentials shadow each other? If they+  -- TODO: can't, we can remove this function+  case List.elemIndices typeVar exts of+    [] ->+      -- We're not replacing any of the existentials, but a global variable+      substGlobalsInExistentials is exts [subst]+    (last -> i) ->+      -- We're replacing an existential. That means we're not touching any+      -- variables that were introduced before it. For all variables after it,+      -- it is as we would replace global variables in them.+      take (i+1) exts ++ substGlobalsInExistentials is (drop (i+1) exts) [subst]+ -- | This checks if the substitution satisfies the invariant from 'TvSbust's -- Note [The substitution invariant]. checkValidSubst@@ -610,7 +672,7 @@   -> Type   -> Type substTyWith tvs tys =-  ASSERT( tvs `equalLength` tys )+  ASSERT( List.equalLength tvs tys )   substTy (zipTvSubst tvs tys)  -- | Ensure that non of the binders in an expression shadow each-other, nor
src/Clash/Core/Term.hs view
@@ -15,27 +15,50 @@  module Clash.Core.Term   ( Term (..)+  , mkAbstraction+  , mkTyLams+  , mkLams+  , mkApps+  , mkTyApps+  , mkTmApps+  , mkTicks   , TmName+  , idToVar+  , varToId   , LetBinding   , Pat (..)+  , patIds+  , patVars   , Alt-  , TickInfo (..), NameMod (..)+  , TickInfo (..)+  , stripTicks+  , partitionTicks+  , NameMod (..)   , PrimInfo (..)   , WorkInfo (..)-  , CoreContext (..), Context, isLambdaBodyCtx, isTickCtx, walkTerm-  , collectArgs, collectArgsTicks, collectTicks, collectTermIds, primArg-  , partitionTicks-  )-where+  , CoreContext (..)+  , Context+  , isLambdaBodyCtx+  , isTickCtx+  , walkTerm+  , collectArgs+  , collectArgsTicks+  , collectTicks+  , collectTermIds+  , collectBndrs+  , primArg+  ) where  -- External Modules import Control.DeepSeq import Data.Binary                             (Binary)+import Data.Coerce                             (coerce) import qualified Data.DList                    as DList import Data.Either                             (lefts, rights)+import Data.Foldable                           (foldl') import Data.Maybe                              (catMaybes) import Data.Hashable                           (Hashable)-import Data.List                               (partition)+import Data.List                               (nub, partition) import Data.Text                               (Text) import GHC.Generics import SrcLoc                                  (SrcSpan)@@ -45,8 +68,9 @@ import Clash.Core.Literal                      (Literal) import Clash.Core.Name                         (Name (..)) import {-# SOURCE #-} Clash.Core.Subst         () -- instance Eq Type-import {-# SOURCE #-} Clash.Core.Type          (Type)-import Clash.Core.Var                          (Id, TyVar)+import {-# SOURCE #-} Clash.Core.Type+import Clash.Core.Var                          (Var(Id), Id)+import Clash.Util                              (curLoc)  -- | Term representation in the CoreHW language: System F + LetRec + Case data Term@@ -126,6 +150,42 @@  type Alt = (Pat,Term) +-- | Get the list of term-binders out of a DataType pattern+patIds :: Pat -> ([TyVar],[Id])+patIds (DataPat _  tvs ids) = (tvs,ids)+patIds _                    = ([],[])++patVars :: Pat -> [Var a]+patVars (DataPat _ tvs ids) = coerce tvs ++ coerce ids+patVars _ = []++-- | Abstract a term over a list of term and type variables+mkAbstraction :: Term -> [Either Id TyVar] -> Term+mkAbstraction = foldr (either Lam TyLam)++-- | Abstract a term over a list of term variables+mkTyLams :: Term -> [TyVar] -> Term+mkTyLams tm = mkAbstraction tm . map Right++-- | Abstract a term over a list of type variables+mkLams :: Term -> [Id] -> Term+mkLams tm = mkAbstraction tm . map Left++-- | Apply a list of types and terms to a term+mkApps :: Term -> [Either Term Type] -> Term+mkApps = foldl' (\e a -> either (App e) (TyApp e) a)++-- | Apply a list of terms to a term+mkTmApps :: Term -> [Term] -> Term+mkTmApps = foldl' App++-- | Apply a list of types to a term+mkTyApps :: Term -> [Type] -> Term+mkTyApps = foldl' TyApp++mkTicks :: Term -> [TickInfo] -> Term+mkTicks tm ticks = foldl' (\e s -> Tick s e) tm (nub ticks)+ -- | Context in which a term appears data CoreContext   = AppFun@@ -194,9 +254,12 @@ isTickCtx (TickC _) = True isTickCtx _         = False +stripTicks :: Term -> Term+stripTicks (Tick _ e) = stripTicks e+stripTicks e = e+ -- | Split a (Type)Application in the applied term and it arguments-collectArgs :: Term-            -> (Term, [Either Term Type])+collectArgs :: Term -> (Term, [Either Term Type]) collectArgs = go []   where     go args (App e1 e2) = go (Left e2:args) e1@@ -204,17 +267,13 @@     go args (Tick _ e)  = go args e     go args e           = (e, args) -collectTicks-  :: Term-  -> (Term, [TickInfo])+collectTicks :: Term -> (Term, [TickInfo]) collectTicks = go []  where   go ticks (Tick s e) = go (s:ticks) e   go ticks e          = (e,ticks) -collectArgsTicks-  :: Term-  -> (Term, [Either Term Type], [TickInfo])+collectArgsTicks :: Term -> (Term, [Either Term Type], [TickInfo]) collectArgsTicks = go [] []  where   go args ticks (App e1 e2) = go (Left e2:args) ticks     e1@@ -222,6 +281,14 @@   go args ticks (Tick s e)  = go args           (s:ticks) e   go args ticks e           = (e, args, ticks) +-- | Split a (Type)Abstraction in the bound variables and the abstracted term+collectBndrs :: Term -> ([Either Id TyVar], Term)+collectBndrs = go []+ where+  go bs (Lam v e')    = go (Left v:bs) e'+  go bs (TyLam tv e') = go (Right tv:bs) e'+  go bs e'            = (reverse bs,e')+ -- | Given a function application, find the primitive it's applied. Yields -- Nothing if given term is not an application or if it is not a primitive. primArg@@ -285,3 +352,14 @@   pat (DataPat _ _ ids) = ids   pat (LitPat _) = []   pat DefaultPat = []++-- | Make variable reference out of term variable+idToVar :: Id -> Term+idToVar i@(Id {}) = Var i+idToVar tv        = error $ $(curLoc) ++ "idToVar: tyVar: " ++ show tv++-- | Make a term variable out of a variable reference+varToId :: Term -> Id+varToId (Var i) = i+varToId e       = error $ $(curLoc) ++ "varToId: not a var: " ++ show e+
+ src/Clash/Core/TermInfo.hs view
@@ -0,0 +1,230 @@+{-# LANGUAGE QuasiQuotes #-}++module Clash.Core.TermInfo where++import Data.Text.Prettyprint.Doc (line)++import Clash.Core.DataCon+import Clash.Core.FreeVars+import Clash.Core.Literal+import Clash.Core.Pretty+import Clash.Core.Subst+import Clash.Core.Term+import Clash.Core.TyCon (TyConMap)+import Clash.Core.Type+import Clash.Core.Var+import Clash.Core.VarEnv+import Clash.Debug (debugIsOn)+import Clash.Util+import Clash.Util.Interpolate as I++termSize :: Term -> Word+termSize (Var {})     = 1+termSize (Data {})    = 1+termSize (Literal {}) = 1+termSize (Prim {})    = 1+termSize (Lam _ e)    = termSize e + 1+termSize (TyLam _ e)  = termSize e+termSize (App e1 e2)  = termSize e1 + termSize e2+termSize (TyApp e _)  = termSize e+termSize (Cast e _ _) = termSize e+termSize (Tick _ e)   = termSize e+termSize (Letrec bndrs e) = sum (bodySz:bndrSzs)+ where+  bndrSzs = map (termSize . snd) bndrs+  bodySz  = termSize e+termSize (Case subj _ alts) = sum (subjSz:altSzs)+ where+  subjSz = termSize subj+  altSzs = map (termSize . snd) alts++-- | Determine the type of a term+termType :: TyConMap -> Term -> Type+termType m e = case e of+  Var t          -> varType t+  Data dc        -> dcType dc+  Literal l      -> literalType l+  Prim t         -> primType t+  Lam v e'       -> mkFunTy (varType v) (termType m e')+  TyLam tv e'    -> ForAllTy tv (termType m e')+  App _ _        -> case collectArgs e of+                      (fun, args) -> applyTypeToArgs e m (termType m fun) args+  TyApp _ _      -> case collectArgs e of+                      (fun, args) -> applyTypeToArgs e m (termType m fun) args+  Letrec _ e'    -> termType m e'+  Case _ ty _    -> ty+  Cast _ _ ty2   -> ty2+  Tick _ e'      -> termType m e'++-- | Get the result type of a polymorphic function given a list of arguments+applyTypeToArgs+  :: Term+  -> TyConMap+  -> Type+  -> [Either Term Type]+  -> Type+applyTypeToArgs e m opTy args = go opTy args+ where+  go opTy' []               = opTy'+  go opTy' (Right ty:args') = goTyArgs opTy' [ty] args'+  go opTy' (Left _:args')   = case splitFunTy m opTy' of+    Just (_,resTy) -> go resTy args'+    _ -> error $ unlines ["applyTypeToArgs:"+                         ,"Expression: " ++ showPpr e+                         ,"Type: " ++ showPpr opTy+                         ,"Args: " ++ unlines (map (either showPpr showPpr) args)+                         ]++  goTyArgs opTy' revTys (Right ty:args') = goTyArgs opTy' (ty:revTys) args'+  goTyArgs opTy' revTys args'            = go (piResultTys m opTy' (reverse revTys)) args'++-- | Like 'piResultTyMaybe', but errors out when a type application is not+-- valid.+--+-- Do not iterate 'piResultTy', because it's inefficient to substitute one+-- variable at a time; instead use 'piResultTys'+piResultTy+  :: HasCallStack+  => TyConMap+  -> Type+  -> Type+  -> Type+piResultTy m ty arg = case piResultTyMaybe m ty arg of+  Just res -> res+  Nothing  -> pprPanic "piResultTy" (ppr ty <> line <> ppr arg)++-- | Like 'piResultTys' but for a single argument.+--+-- Do not iterate 'piResultTyMaybe', because it's inefficient to substitute one+-- variable at a time; instead use 'piResultTys'+piResultTyMaybe+  :: HasCallStack+  => TyConMap+  -> Type+  -> Type+  -> Maybe Type+piResultTyMaybe m ty arg+  | Just ty' <- coreView1 m ty+  = piResultTyMaybe m ty' arg+  | FunTy a res <- tyView ty+  = if debugIsOn && not (aeqType a arg) then error [I.i|+      Unexpected application. A function with type:++        #{showPpr ty}++      Got applied to an argument of type:++        #{showPpr arg}+    |]+    else+      Just res+  | ForAllTy tv res <- ty+  = let emptySubst = mkSubst (mkInScopeSet (tyFVsOfTypes [arg,res]))+    in  Just (substTy (extendTvSubst emptySubst tv arg) res)+  | otherwise+  = Nothing++-- | @(piResultTys f_ty [ty1, ..., tyn])@ give sthe type of @(f ty1 .. tyn)@+-- where @f :: f_ty@+--+-- 'piResultTys' is interesting because:+--+--    1. 'f_ty' may have more foralls than there are args+--    2. Less obviously, it may have fewer foralls+--+-- Fore case 2. think of:+--+--   piResultTys (forall a . a) [forall b.b, Int]+--+-- This really can happen, such as situations involving 'undefined's type:+--+--   undefined :: forall a. a+--+--   undefined (forall b. b -> b) Int+--+-- This term should have the type @(Int -> Int)@, but notice that there are+-- more type args than foralls in 'undefined's type.+--+-- For efficiency reasons, when there are no foralls, we simply drop arrows from+-- a function type/kind.+piResultTys+  :: HasCallStack+  => TyConMap+  -> Type+  -> [Type]+  -> Type+piResultTys _ ty [] = ty+piResultTys m ty origArgs@(arg:args)+  | Just ty' <- coreView1 m ty+  = piResultTys m ty' origArgs+  | FunTy a res <- tyView ty+  = if debugIsOn && not (aeqType a arg) then error [I.i|+      Unexpected application. A function with type:++        #{showPpr ty}++      Got applied to an argument of type:++        #{showPpr arg}+    |]+    else+      piResultTys m res args+  | ForAllTy tv res <- ty+  = go (extendVarEnv tv arg emptyVarEnv) res args+  | otherwise+  = pprPanic "piResultTys1" (ppr ty <> line <> ppr origArgs)+ where+  inScope = mkInScopeSet (tyFVsOfTypes (ty:origArgs))++  go env ty' [] = substTy (mkTvSubst inScope env) ty'+  go env ty' allArgs@(arg':args')+    | Just ty'' <- coreView1 m ty'+    = go env ty'' allArgs+    | FunTy _ res <- tyView ty'+    = go env res args'+    | ForAllTy tv res <- ty'+    = go (extendVarEnv tv arg' env) res args'+    | VarTy tv <- ty'+    , Just ty'' <- lookupVarEnv tv env+      -- Deals with (piResultTys  (forall a.a) [forall b.b, Int])+    = piResultTys m ty'' allArgs+    | otherwise+    = pprPanic "piResultTys2" (ppr ty' <> line <> ppr origArgs <> line <> ppr allArgs)++-- | Does a term have a function type?+isFun :: TyConMap -> Term -> Bool+isFun m t = isFunTy m (termType m t)++-- | Does a term have a function or polymorphic type?+isPolyFun :: TyConMap -> Term -> Bool+isPolyFun m t = isPolyFunCoreTy m (termType m t)++-- | Is a term a term-abstraction?+isLam :: Term -> Bool+isLam (Lam {}) = True+isLam _        = False++-- | Is a term a recursive let-binding?+isLet :: Term -> Bool+isLet (Letrec {}) = True+isLet _           = False++-- | Is a term a variable reference?+isVar :: Term -> Bool+isVar (Var {}) = True+isVar _        = False++isLocalVar :: Term -> Bool+isLocalVar (Var v) = isLocalId v+isLocalVar _ = False++-- | Is a term a datatype constructor?+isCon :: Term -> Bool+isCon (Data {}) = True+isCon _         = False++-- | Is a term a primitive?+isPrim :: Term -> Bool+isPrim (Prim {}) = True+isPrim _         = False+
src/Clash/Core/Type.hs view
@@ -63,6 +63,7 @@ import           Data.Coerce            (coerce) import           Data.Hashable          (Hashable) import           Data.List              (foldl')+import           Data.List.Extra        (splitAtList) import           Data.Maybe             (isJust, mapMaybe) import           GHC.Base               (isTrue#,(==#)) import           GHC.Generics           (Generic(..))@@ -452,10 +453,8 @@       Just ty' | ty' `aeqType` ty -> Just s       _ -> Nothing     go ty1 (reduceTypeFamily tcm -> Just ty2) = go ty1 ty2 -- See [Note: lazy type families]-    go ty1@(LitTy _) ty2 = if ty1 `aeqType` ty2 then Just s else Nothing-    go (tyView -> TyConApp tc argTys) (tyView -> TyConApp tc' argTys')-      | tc == tc'-      = foldl' (funSubst tcm) (Just s) (zip argTys argTys')+    -- [Note] funSubst FunTy+    --     -- Whenever type classes have associated types whose instances 'map' to     -- functions, we try to find substitutions in the LHS and RHS of these     -- (type-level) functions. Because we use @funSubst@ recursively, we@@ -472,9 +471,17 @@     -- matching against `Char -> Char` we'd find a duplicate `a -> Char`. We     -- can't think of any (type-checking) cases where these mappings would map     -- to different types, so this is OK for our purposes.-    go (tyView -> FunTy a b) (tyView -> FunTy a' b') =-      (++) <$> funSubst tcm (Just s) (a, a')-           <*> funSubst tcm (Just s) (b, b')+    go (AppTy a1 r1) (AppTy a2 r2) = do+      s1 <- funSubst tcm (Just s) (a1, a2)+      funSubst tcm (Just s1) (r1, r2)++    go ty1@(ConstTy _) ty2 =+      -- Looks through AnnType+      if ty1 `aeqType` ty2 then Just s else Nothing++    go ty1@(LitTy _) ty2 =+      -- Looks through AnnType+      if ty1 `aeqType` ty2 then Just s else Nothing      go _ _ = Nothing 
src/Clash/Core/Util.hs view
@@ -17,18 +17,15 @@ import           Control.Concurrent.Supply     (Supply, freshId) import qualified Control.Lens                  as Lens import Control.Monad.Trans.Except              (Except, throwE)-import           Data.Coerce                   (coerce) import qualified Data.HashSet                  as HashSet import qualified Data.Graph                    as Graph-import Data.List-  (foldl', mapAccumR, elemIndices, nub)+import Data.List                               (foldl', mapAccumR)+import Data.List.Extra                         (zipEqual) import Data.Maybe   (fromJust, isJust, mapMaybe, catMaybes) import qualified Data.Set                      as Set import qualified Data.Set.Lens                 as Lens-import qualified Data.String.Interpolate       as I import qualified Data.Text                     as T-import           Data.Text.Prettyprint.Doc     (line) #if !MIN_VERSION_base(4,11,0) import           Data.Semigroup #endif@@ -37,541 +34,22 @@ import           Unique                  (getKey)  import Clash.Core.DataCon-  (DataCon (MkData), dcType, dcUnivTyVars, dcExtTyVars, dcArgTys)-import Clash.Core.FreeVars-  (tyFVsOfTypes, typeFreeVars, freeLocalIds)-import Clash.Core.Literal                      (literalType)+import Clash.Core.EqSolver+import Clash.Core.FreeVars               (tyFVsOfTypes, typeFreeVars, freeLocalIds) import Clash.Core.Name   (Name (..), OccName, mkUnsafeInternalName, mkUnsafeSystemName)-import Clash.Core.Pretty                       (ppr, showPpr)+import Clash.Core.Pretty                 (showPpr) import Clash.Core.Subst-  (extendTvSubst, mkSubst, mkTvSubst, substTy, substTyWith,-   substTyInVar, extendTvSubstList, aeqType) import Clash.Core.Term-  (LetBinding, Pat (..), PrimInfo (..), Term (..), Alt, WorkInfo (..),-   TickInfo (..), collectArgs)+import Clash.Core.TyCon                  (TyConMap, tyConDataCons) import Clash.Core.Type-  (Kind, LitTy (..), Type (..), TypeView (..),-   coreView, coreView1, isFunTy, isPolyFunCoreTy, mkFunTy, splitFunTy, tyView,-   undefinedTy, isTypeFamilyApplication)-import Clash.Core.TyCon-  (TyConMap, tyConDataCons)-import Clash.Core.TysPrim                      (typeNatKind)-import Clash.Core.Var-  (Id, TyVar, Var (..), isLocalId, mkLocalId, mkTyVar)+import Clash.Core.TysPrim                (typeNatKind)+import Clash.Core.Var                    (Id, Var(..), mkLocalId, mkTyVar) import Clash.Core.VarEnv-  (InScopeSet, VarEnv, emptyVarEnv, extendInScopeSet, extendVarEnv,-   lookupVarEnv, mkInScopeSet, uniqAway, extendInScopeSetList, unionInScope,-   mkVarSet, unionVarSet, unitVarSet, emptyVarSet)+import Clash.Debug                       (traceIf) import Clash.Unique import Clash.Util --- | Type environment/context-type Gamma = VarEnv Type--- | Kind environment/context-type Delta = VarEnv Kind---- | Given the left and right side of an equation, normalize it such that--- equations of the following forms:------     * 5     ~ n + 2---     * 5     ~ 2 + n---     * n + 2 ~ 5---     * 2 + n ~ 5------ are returned as (5, 2, n)-normalizeAdd-  :: (Type, Type)-  -> Maybe (Integer, Integer, Type)-normalizeAdd (a, b) = do-  (n, rhs) <- lhsLit a b-  case tyView rhs of-    TyConApp (nameOcc -> "GHC.TypeNats.+") [left, right] -> do-      (m, o) <- lhsLit left right-      return (n, m, o)-    _ ->-      Nothing- where-  lhsLit x                 (LitTy (NumTy n)) = Just (n, x)-  lhsLit (LitTy (NumTy n)) y                 = Just (n, y)-  lhsLit _                 _                 = Nothing---- | Data type that indicates what kind of solution (if any) was found-data TypeEqSolution-  = Solution (TyVar, Type)-  -- ^ Solution was found. Variable equals some integer.-  | AbsurdSolution-  -- ^ A solution was found, but it involved negative naturals.-  | NoSolution-  -- ^ Given type wasn't an equation, or it was unsolvable.-    deriving (Show, Eq)--catSolutions :: [TypeEqSolution] -> [(TyVar, Type)]-catSolutions = mapMaybe getSol- where-  getSol (Solution s) = Just s-  getSol _ = Nothing---- | Solve given equations and return all non-absurd solutions-solveNonAbsurds :: TyConMap -> [(Type, Type)] -> [(TyVar, Type)]-solveNonAbsurds _tcm [] = []-solveNonAbsurds tcm (eq:eqs) =-  solved ++ solveNonAbsurds tcm eqs- where-  solvers = [pure . solveAdd, solveEq tcm]-  solved = catSolutions (concat [s eq | s <- solvers])---- | Solve simple equalities such as:------   * a ~ 3---   * 3 ~ a---   * SomeType a b ~ SomeType 3 5---   * SomeType 3 5 ~ SomeType a b---   * SomeType a 5 ~ SomeType 3 b----solveEq :: TyConMap -> (Type, Type) -> [TypeEqSolution]-solveEq tcm (coreView tcm -> left, coreView tcm -> right) =-  case (left, right) of-    (VarTy tyVar, ConstTy {}) ->-      -- a ~ 3-      [Solution (tyVar, right)]-    (ConstTy {}, VarTy tyVar) ->-      -- 3 ~ a-      [Solution (tyVar, left)]-    (ConstTy {}, ConstTy {}) ->-      -- Int /= Char-      if left /= right then [AbsurdSolution] else []-    (LitTy {}, LitTy {}) ->-      -- 3 /= 5-      if left /= right then [AbsurdSolution] else []-    _ ->-      -- The call to 'coreView' at the start of 'solveEq' should have reduced-      -- all solvable type families. If we encounter one here that means the-      -- type family is stuck (and that we shouldn't compare it to anything!).-      if any (isTypeFamilyApplication tcm) [left, right] then-        []-      else-        case (tyView left, tyView right) of-          (TyConApp leftNm leftTys, TyConApp rightNm rightTys) ->-            -- SomeType a b ~ SomeType 3 5 (or other way around)-            if leftNm == rightNm then-              concat (map (solveEq tcm) (zip leftTys rightTys))-            else-              [AbsurdSolution]-          _ ->-            []---- | Solve equations supported by @normalizeAdd@. See documentation of--- @TypeEqSolution@ to understand the return value.-solveAdd-  :: (Type, Type)-  -> TypeEqSolution-solveAdd ab =-  case normalizeAdd ab of-    Just (n, m, VarTy tyVar) ->-      if n >= 0 && m >= 0 && n - m >= 0 then-        Solution (tyVar, (LitTy (NumTy (n - m))))-      else-        AbsurdSolution-    _ ->-      NoSolution---- | If type is an equation, return LHS and RHS.-typeEq-  :: TyConMap-  -> Type-  -> Maybe (Type, Type)-typeEq tcm ty =- case tyView (coreView tcm ty) of-  TyConApp (nameOcc -> "GHC.Prim.~#") [_, _, left, right] ->-    Just (coreView tcm left, coreView tcm right)-  _ ->-    Nothing---- | Get constraint equations-altEqs-  :: TyConMap-  -> Alt-  -> [(Type, Type)]-altEqs tcm (pat, _term) =- catMaybes (map (typeEq tcm . varType) (snd (patIds pat)))---- | Tests for unreachable alternative due to types being "absurd". See--- @isAbsurdEq@ for more info.-isAbsurdAlt-  :: TyConMap-  -> Alt-  -> Bool-isAbsurdAlt tcm alt =-  any (isAbsurdEq tcm) (altEqs tcm alt)---- | Determines if an "equation" obtained through @altEqs@ or @typeEq@ is--- absurd. That is, it tests if two types that are definitely not equal are--- asserted to be equal OR if the computation of the types yield some absurd--- (intermediate) result such as -1.-isAbsurdEq-  :: TyConMap-  -> (Type, Type)-  -> Bool-isAbsurdEq tcm ((left0, right0)) =-  case (coreView tcm left0, coreView tcm right0) of-    (solveAdd -> AbsurdSolution) -> True-    lr -> any (==AbsurdSolution) (solveEq tcm lr)---- Safely substitute global type variables in a list of potentially--- shadowing type variables.-substGlobalsInExistentials-  :: HasCallStack-  => InScopeSet-  -- ^ Variables in scope-  -> [TyVar]-  -- ^ List of existentials to apply the substitution for-  -> [(TyVar, Type)]-  -- ^ Substitutions-  -> [TyVar]-substGlobalsInExistentials is exts substs0 = result-  -- TODO: Is is actually possible that existentials shadow each other? If they-  -- TODO: can't, we can remove this function-  where-    iss     = scanl extendInScopeSet is exts-    substs1 = map (\is_ -> extendTvSubstList (mkSubst is_) substs0) iss-    result  = zipWith substTyInVar substs1 exts---- | Safely substitute type variables in a list of existentials. This function--- will account for cases where existentials shadow each other.-substInExistentialsList-  :: HasCallStack-  => InScopeSet-  -- ^ Variables in scope-  -> [TyVar]-  -- ^ List of existentials to apply the substitution for-  -> [(TyVar, Type)]-  -- ^ Substitutions-  -> [TyVar]-substInExistentialsList is exts substs =-  foldl (substInExistentials is) exts substs---- | Safely substitute a type variable in a list of existentials. This function--- will account for cases where existentials shadow each other.-substInExistentials-  :: HasCallStack-  => InScopeSet-  -- ^ Variables in scope-  -> [TyVar]-  -- ^ List of existentials to apply the substitution for-  -> (TyVar, Type)-  -- ^ Substitution-  -> [TyVar]-substInExistentials is exts subst@(typeVar, _type) =-  -- TODO: Is is actually possible that existentials shadow each other? If they-  -- TODO: can't, we can remove this function-  case elemIndices typeVar exts of-    [] ->-      -- We're not replacing any of the existentials, but a global variable-      substGlobalsInExistentials is exts [subst]-    (last -> i) ->-      -- We're replacing an existential. That means we're not touching any-      -- variables that were introduced before it. For all variables after it,-      -- it is as we would replace global variables in them.-      take (i+1) exts ++ substGlobalsInExistentials is (drop (i+1) exts) [subst]---- | Determine the type of a term-termType-  :: TyConMap-  -> Term-  -> Type-termType m e = case e of-  Var t          -> varType t-  Data dc        -> dcType dc-  Literal l      -> literalType l-  Prim t         -> primType t-  Lam v e'       -> mkFunTy (varType v) (termType m e')-  TyLam tv e'    -> ForAllTy tv (termType m e')-  App _ _        -> case collectArgs e of-                      (fun, args) -> applyTypeToArgs e m (termType m fun) args-  TyApp _ _      -> case collectArgs e of-                      (fun, args) -> applyTypeToArgs e m (termType m fun) args-  Letrec _ e'    -> termType m e'-  Case _ ty _    -> ty-  Cast _ _ ty2   -> ty2-  Tick _ e'      -> termType m e'---- | Split a (Type)Abstraction in the bound variables and the abstracted term-collectBndrs :: Term-             -> ([Either Id TyVar], Term)-collectBndrs = go []-  where-    go bs (Lam v e')    = go (Left v:bs) e'-    go bs (TyLam tv e') = go (Right tv:bs) e'-    go bs e'            = (reverse bs,e')---- | Get the result type of a polymorphic function given a list of arguments-applyTypeToArgs-  :: Term-  -> TyConMap-  -> Type-  -> [Either Term Type]-  -> Type-applyTypeToArgs e m opTy args = go opTy args- where-  go opTy' []               = opTy'-  go opTy' (Right ty:args') = goTyArgs opTy' [ty] args'-  go opTy' (Left _:args')   = case splitFunTy m opTy' of-    Just (_,resTy) -> go resTy args'-    _ -> error $ unlines ["applyTypeToArgs:"-                         ,"Expression: " ++ showPpr e-                         ,"Type: " ++ showPpr opTy-                         ,"Args: " ++ unlines (map (either showPpr showPpr) args)-                         ]--  goTyArgs opTy' revTys (Right ty:args') = goTyArgs opTy' (ty:revTys) args'-  goTyArgs opTy' revTys args'            = go (piResultTys m opTy' (reverse revTys)) args'---- | Like 'piResultTyMaybe', but errors out when a type application is not--- valid.------ Do not iterate 'piResultTy', because it's inefficient to substitute one--- variable at a time; instead use 'piResultTys'-piResultTy-  :: HasCallStack-  => TyConMap-  -> Type-  -> Type-  -> Type-piResultTy m ty arg = case piResultTyMaybe m ty arg of-  Just res -> res-  Nothing  -> pprPanic "piResultTy" (ppr ty <> line <> ppr arg)---- | Like 'piResultTys' but for a single argument.------ Do not iterate 'piResultTyMaybe', because it's inefficient to substitute one--- variable at a time; instead use 'piResultTys'-piResultTyMaybe-  :: HasCallStack-  => TyConMap-  -> Type-  -> Type-  -> Maybe Type-piResultTyMaybe m ty arg-  | Just ty' <- coreView1 m ty-  = piResultTyMaybe m ty' arg-  | FunTy a res <- tyView ty-  = if debugIsOn && not (aeqType a arg) then error [I.i|-      Unexpected application. A function with type:--        #{showPpr ty}--      Got applied to an argument of type:--        #{showPpr arg}-    |]-    else-      Just res-  | ForAllTy tv res <- ty-  = let emptySubst = mkSubst (mkInScopeSet (tyFVsOfTypes [arg,res]))-    in  Just (substTy (extendTvSubst emptySubst tv arg) res)-  | otherwise-  = Nothing---- | @(piResultTys f_ty [ty1, ..., tyn])@ give sthe type of @(f ty1 .. tyn)@--- where @f :: f_ty@------ 'piResultTys' is interesting because:------    1. 'f_ty' may have more foralls than there are args---    2. Less obviously, it may have fewer foralls------ Fore case 2. think of:------   piResultTys (forall a . a) [forall b.b, Int]------ This really can happen, such as situations involving 'undefined's type:------   undefined :: forall a. a------   undefined (forall b. b -> b) Int------ This term should have the type @(Int -> Int)@, but notice that there are--- more type args than foralls in 'undefined's type.------ For efficiency reasons, when there are no foralls, we simply drop arrows from--- a function type/kind.-piResultTys-  :: HasCallStack-  => TyConMap-  -> Type-  -> [Type]-  -> Type-piResultTys _ ty [] = ty-piResultTys m ty origArgs@(arg:args)-  | Just ty' <- coreView1 m ty-  = piResultTys m ty' origArgs-  | FunTy a res <- tyView ty-  = if debugIsOn && not (aeqType a arg) then error [I.i|-      Unexpected application. A function with type:--        #{showPpr ty}--      Got applied to an argument of type:--        #{showPpr arg}-    |]-    else-      piResultTys m res args-  | ForAllTy tv res <- ty-  = go (extendVarEnv tv arg emptyVarEnv) res args-  | otherwise-  = pprPanic "piResultTys1" (ppr ty <> line <> ppr origArgs)- where-  inScope = mkInScopeSet (tyFVsOfTypes (ty:origArgs))--  go env ty' [] = substTy (mkTvSubst inScope env) ty'-  go env ty' allArgs@(arg':args')-    | Just ty'' <- coreView1 m ty'-    = go env ty'' allArgs-    | FunTy _ res <- tyView ty'-    = go env res args'-    | ForAllTy tv res <- ty'-    = go (extendVarEnv tv arg' env) res args'-    | VarTy tv <- ty'-    , Just ty'' <- lookupVarEnv tv env-      -- Deals with (piResultTys  (forall a.a) [forall b.b, Int])-    = piResultTys m ty'' allArgs-    | otherwise-    = pprPanic "piResultTys2" (ppr ty' <> line <> ppr origArgs <> line <> ppr allArgs)---- | Get the list of term-binders out of a DataType pattern-patIds :: Pat -> ([TyVar],[Id])-patIds (DataPat _  tvs ids) = (tvs,ids)-patIds _                    = ([],[])--patVars :: Pat -> [Var a]-patVars (DataPat _ tvs ids) = coerce tvs ++ coerce ids-patVars _ = []---- | Abstract a term over a list of term and type variables-mkAbstraction :: Term-              -> [Either Id TyVar]-              -> Term-mkAbstraction = foldr (either Lam TyLam)---- | Abstract a term over a list of term variables-mkTyLams :: Term-         -> [TyVar]-         -> Term-mkTyLams tm = mkAbstraction tm . map Right---- | Abstract a term over a list of type variables-mkLams :: Term-       -> [Id]-       -> Term-mkLams tm = mkAbstraction tm . map Left---- | Apply a list of types and terms to a term-mkApps :: Term-       -> [Either Term Type]-       -> Term-mkApps = foldl' (\e a -> either (App e) (TyApp e) a)---- | Apply a list of terms to a term-mkTmApps :: Term-         -> [Term]-         -> Term-mkTmApps = foldl' App---- | Apply a list of types to a term-mkTyApps :: Term-         -> [Type]-         -> Term-mkTyApps = foldl' TyApp--mkTicks-  :: Term-  -> [TickInfo]-  -> Term-mkTicks tm ticks = foldl' (\e s -> Tick s e) tm (nub ticks)---- | Does a term have a function type?-isFun :: TyConMap-      -> Term-      -> Bool-isFun m t = isFunTy m (termType m t)---- | Does a term have a function or polymorphic type?-isPolyFun :: TyConMap-          -> Term-          -> Bool-isPolyFun m t = isPolyFunCoreTy m (termType m t)---- | Is a term a term-abstraction?-isLam :: Term-      -> Bool-isLam (Lam {}) = True-isLam _        = False---- | Is a term a recursive let-binding?-isLet :: Term-      -> Bool-isLet (Letrec {}) = True-isLet _           = False---- | Is a term a variable reference?-isVar :: Term-      -> Bool-isVar (Var {}) = True-isVar _        = False--isLocalVar-  :: Term-  -> Bool-isLocalVar (Var v) = isLocalId v-isLocalVar _ = False---- | Is a term a datatype constructor?-isCon :: Term-      -> Bool-isCon (Data {}) = True-isCon _         = False---- | Is a term a primitive?-isPrim :: Term-       -> Bool-isPrim (Prim {}) = True-isPrim _         = False---- | Make variable reference out of term variable-idToVar :: Id-        -> Term-idToVar i@(Id {}) = Var i-idToVar tv        = error $ $(curLoc) ++ "idToVar: tyVar: " ++ showPpr tv---- | Make a term variable out of a variable reference-varToId :: Term-        -> Id-varToId (Var i) = i-varToId e       = error $ $(curLoc) ++ "varToId: not a var: " ++ showPpr e--termSize :: Term-         -> Word-termSize (Var {})     = 1-termSize (Data {})    = 1-termSize (Literal {}) = 1-termSize (Prim {})    = 1-termSize (Lam _ e)    = termSize e + 1-termSize (TyLam _ e)  = termSize e-termSize (App e1 e2)  = termSize e1 + termSize e2-termSize (TyApp e _)  = termSize e-termSize (Cast e _ _) = termSize e-termSize (Tick _ e)   = termSize e-termSize (Letrec bndrs e) = sum (bodySz:bndrSzs)- where-  bndrSzs = map (termSize . snd) bndrs-  bodySz  = termSize e-termSize (Case subj _ alts) = sum (subjSz:altSzs)- where-  subjSz = termSize subj-  altSzs = map (termSize . snd) alts- -- | Create a vector of supplied elements mkVec :: DataCon -- ^ The Nil constructor       -> DataCon -- ^ The Cons (:>) constructor@@ -960,10 +438,6 @@       -- See Note [The substitution invariant]       subst   = extendTvSubstList (mkSubst is) (univTVs `zipEqual` args)   in  map (substTy subst) (dcArgTys dc)--stripTicks :: Term -> Term-stripTicks (Tick _ e) = stripTicks e-stripTicks e = e  -- | Try to reduce an arbitrary type to a literal type (Symbol or Nat), -- and subsequently extract its String representation
src/Clash/Core/VarEnv.hs view
@@ -95,6 +95,7 @@ import           Data.Binary               (Binary) import           Data.Coerce               (coerce) import qualified Data.List                 as List+import qualified Data.List.Extra           as List import           Data.Maybe                (fromMaybe) import           Data.Text.Prettyprint.Doc import           GHC.Exts                  (Any)@@ -102,6 +103,7 @@  import           Clash.Core.Pretty         () import           Clash.Core.Var+import           Clash.Debug               (debugIsOn) import           Clash.Unique import           Clash.Util import           Clash.Pretty@@ -554,7 +556,7 @@ rnTyBndrs   :: RnEnv -> [TyVar] -> [TyVar] -> RnEnv rnTyBndrs env tvs1 tvs2 =-  List.foldl' (\s (l,r) -> rnTyBndr s l r) env (zipEqual tvs1 tvs2)+  List.foldl' (\s (l,r) -> rnTyBndr s l r) env (List.zipEqual tvs1 tvs2)  -- | Look up the renaming of an occurrence in the left term rnOccLId@@ -585,4 +587,4 @@ rnTmBndrs   :: RnEnv -> [Id] -> [Id] -> RnEnv rnTmBndrs env ids1 ids2 =-  List.foldl' (\s (l,r) -> rnTmBndr s l r) env (zipEqual ids1 ids2)+  List.foldl' (\s (l,r) -> rnTmBndr s l r) env (List.zipEqual ids1 ids2)
+ src/Clash/Debug.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE CPP #-}++module Clash.Debug+  ( debugIsOn+  , traceIf+  , traceWith+  , traceShowWith+  , module Debug.Trace+  ) where++import Debug.Trace++debugIsOn :: Bool+#if defined(DEBUG)+debugIsOn = True+#else+debugIsOn = False+#endif++-- | Performs trace when first argument evaluates to 'True'+traceIf :: Bool -> String -> a -> a+traceIf True  msg = trace msg+traceIf False _   = id+{-# INLINE traceIf #-}++traceWith :: (a -> String) -> a -> a+traceWith f a = trace (f a) a++traceShowWith :: Show b => (a -> b) -> a -> a+traceShowWith f a = trace (show (f a)) a+
src/Clash/Driver.hs view
@@ -85,6 +85,7 @@   (Id, varName, varUniq, varType) import           Clash.Core.VarEnv   (elemVarEnv, emptyVarEnv, lookupVarEnv)+import           Clash.Debug                      (debugIsOn) import           Clash.Driver.Types import           Clash.Netlist                    (genNetlist) import           Clash.Netlist.Util               (genComponentName, genTopComponentName)@@ -107,7 +108,7 @@ import           Clash.Util.Interpolate           (i) import           Clash.Util   (ClashException(..), HasCallStack, first, reportTimeDiff,-   wantedLanguageExtensions, unwantedLanguageExtensions, debugIsOn)+   wantedLanguageExtensions, unwantedLanguageExtensions) import           Clash.Util.Graph                 (reverseTopSort)  -- | Worker function of 'splitTopEntityT'@@ -340,8 +341,8 @@             let terms = callGraphBindings bindingsMap bench in             Just (hash (annM, primMapHash, show clashModDate, terms, optsHash)) -    let succesFlagsI = (opt_inlineLimit opts,opt_specLimit opts,opt_floatSupport opts)-        manifestI    = Manifest (topHash,benchHashM) succesFlagsI [] [] [] [] []+    let successFlagsI = (opt_inlineLimit opts,opt_specLimit opts,opt_floatSupport opts)+        manifestI    = Manifest (topHash,benchHashM) successFlagsI [] [] [] [] []      let       manFile =@@ -357,13 +358,13 @@                   (\man ->                     let allowCache (inl0,spec0,fl0) (inl1,spec1,fl1) =                           inl0 <= inl1 && spec0 <= spec1 && (not (fl0 && not fl1))-                        flagsAllowCache = allowCache (succesFlags man) succesFlagsI+                        flagsAllowCache = allowCache (successFlags man) successFlagsI                     in  (flagsAllowCache && fst (manifestHash man) == topHash                         ,flagsAllowCache && snd (manifestHash man) == benchHashM                         ,man { manifestHash = (topHash,benchHashM)-                             , succesFlags  = if flagsAllowCache-                                                 then succesFlags man-                                                 else succesFlagsI+                             , successFlags  = if flagsAllowCache+                                                 then successFlags man+                                                 else successFlagsI                              }                         ))                   manM)
src/Clash/Driver/Types.hs view
@@ -189,7 +189,7 @@   { manifestHash :: (Int,Maybe Int)     -- ^ Hash of the TopEntity and all its dependencies     --   + (maybe) Hash of the TestBench and all its dependencies-  , succesFlags  :: (Int,Int,Bool)+  , successFlags  :: (Int,Int,Bool)     -- ^ Compiler flags used to achieve successful compilation:     --     --   * opt_inlineLimit
src/Clash/Netlist.hs view
@@ -33,6 +33,7 @@ import qualified Data.HashMap.Strict              as HashMapS import qualified Data.HashMap.Lazy                as HashMap import           Data.List                        (elemIndex, partition, sortOn)+import           Data.List.Extra                  (zipEqual) import           Data.Maybe   (catMaybes, listToMaybe, mapMaybe, fromMaybe) import qualified Data.Set                         as Set@@ -57,13 +58,14 @@ import           Clash.Core.Name                  (Name(..)) import           Clash.Core.Pretty                (showPpr) import           Clash.Core.Term-  (Alt, Pat (..), Term (..), TickInfo (..), PrimInfo(primName), collectArgs, collectArgsTicks, collectTicks)+  ( Alt, Pat (..), Term (..), TickInfo (..), PrimInfo(primName), collectArgs+  , collectArgsTicks, collectTicks, mkApps, mkTicks, stripTicks) import qualified Clash.Core.Term                  as Core+import           Clash.Core.TermInfo              (termType) import           Clash.Core.Type   (Type (..), coreView1, splitFunForallTy, splitCoreFunForallTy) import           Clash.Core.TyCon                 (TyConMap)-import           Clash.Core.Util-  (mkApps, mkTicks, splitShouldSplit, stripTicks, termType)+import           Clash.Core.Util                  (splitShouldSplit) import           Clash.Core.Var                   (Id, Var (..), isGlobalId) import           Clash.Core.VarEnv   (VarEnv, eltsVarEnv, emptyInScopeSet, emptyVarEnv, extendVarEnv, lookupVarEnv,@@ -623,7 +625,7 @@           -- Filter void arguments, but make sure to render their declarations:           let             argTypeExprs = zip argHWTys (zip argTys argExprs)-            filteredTypeExprs = filterOnFst (not . isVoidMaybe True) argTypeExprs+            filteredTypeExprs = fmap snd $ filter (not . isVoidMaybe True . fst) argTypeExprs             (argTysFiltered, argsFiltered) = unzip filteredTypeExprs            let compOutp = (\(_,x,_) -> x) <$> listToMaybe co
src/Clash/Netlist/BlackBox.hs view
@@ -12,19 +12,21 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE QuasiQuotes #-}  module Clash.Netlist.BlackBox where  import           Control.Exception             (throw) import           Control.Lens                  ((<<%=),(%=)) import qualified Control.Lens                  as Lens-import           Control.Monad                 (when, replicateM)+import           Control.Monad                 (when, replicateM, zipWithM) import           Control.Monad.IO.Class        (liftIO) import           Data.Char                     (ord) import           Data.Either                   (lefts, partitionEithers) import qualified Data.HashMap.Lazy             as HashMap import qualified Data.IntMap                   as IntMap import           Data.List                     (elemIndex, partition)+import           Data.List.Extra               (countEq, mapAccumLM) import           Data.Maybe                    (catMaybes, fromJust, fromMaybe) import           Data.Semigroup.Monad import qualified Data.Set                      as Set@@ -56,12 +58,13 @@ import           Clash.Core.Pretty             (showPpr) import           Clash.Core.Subst              (extendIdSubst, mkSubst, substTm) import           Clash.Core.Term               as C-  (PrimInfo (..), Term (..), WorkInfo (..), collectArgs, collectArgsTicks)+  (PrimInfo (..), Term (..), WorkInfo (..), collectArgs, collectArgsTicks, collectBndrs, mkApps)+import           Clash.Core.TermInfo import           Clash.Core.Type               as C   (Type (..), ConstTy (..), TypeView (..), mkFunTy, splitFunTys, splitFunTy, tyView) import           Clash.Core.TyCon              as C (TyConMap, tyConDataCons) import           Clash.Core.Util-  (collectBndrs, inverseTopSortLetBindings, isFun, mkApps, splitShouldSplit, termType)+  (inverseTopSortLetBindings, splitShouldSplit) import           Clash.Core.Var                as V   (Id, Var (..), mkLocalId, modifyVarName) import           Clash.Core.VarEnv@@ -70,6 +73,7 @@   (genComponent, mkDcApplication, mkDeclarations, mkExpr, mkNetDecl,    mkProjection, mkSelection, mkFunApp, mkDeclarations') import qualified Clash.Backend                 as Backend+import           Clash.Debug                   (debugIsOn) import           Clash.Driver.Types   (opt_primWarn, opt_color, ClashOpts) import           Clash.Netlist.BlackBox.Types  as B@@ -82,6 +86,7 @@ import           Clash.Signal.Internal         (ActiveEdge (..)) import           Clash.Unique                  (lookupUniqMap') import           Clash.Util+import qualified Clash.Util.Interpolate        as I  -- | Emits (colorized) warning to stderr warn@@ -115,7 +120,7 @@     -- Make context inputs     let resNm = nameOcc (varName resId)     resTy <- unsafeCoreTypeToHWTypeM' $(curLoc) (V.varType resId)-    (imps,impDecls) <- unzip <$> mapM (mkArgument resNm) termArgs+    (imps,impDecls) <- unzip <$> zipWithM (mkArgument bbName resNm) [0..] termArgs     (funs,funDecls) <-       mapAccumLM         (addFunction (V.varType resId))@@ -191,13 +196,17 @@   _                -> False  mkArgument-  :: Identifier+  :: TextS.Text+  -- ^ Blackbox function name+  -> Identifier   -- ^ LHS of the original let-binder+  -> Int+  -- ^ Argument n (zero-indexed). Used for error message.   -> Term   -> NetlistMonad ( (Expr,HWType,Bool)                   , [Declaration]                   )-mkArgument bndr e = do+mkArgument bbName bndr nArg e = do     tcm   <- Lens.use tcCache     let ty = termType tcm e     iw    <- Lens.use intWidth@@ -239,9 +248,20 @@         (Case scrut ty' [alt],[],_) -> do           (projection,decls) <- mkProjection False (NetlistId bndr ty) scrut ty' alt           return ((projection,hwTy,False),decls)-        _ ->-          return ((Identifier (error ($(curLoc) ++ "Forced to evaluate unexpected function argument: " ++ eTyMsg)) Nothing-                  ,hwTy,False),[])+        (Letrec _bnds _term, [], _ticks) -> do+          (exprN, letDecls) <- mkExpr False Concurrent (NetlistId bndr ty) e+          return ((exprN,hwTy,False),letDecls)+        _ -> do+          let errMsg = [I.i|+            Forced to evaluate unexpected function argument:++              #{eTyMsg}++            in 'mkArgument' for argument #{nArg} of blackbox #{show bbName}.+          |]++          return ((Identifier (error ($(curLoc) ++ errMsg)) Nothing, hwTy, False), [])+     return ((e',t,l),d)  -- | Extract a compiled primitive from a guarded primitive. Emit a warning if
src/Clash/Netlist/BlackBox/Util.hs view
@@ -27,6 +27,7 @@ import           Data.Hashable                   (Hashable (..)) import qualified Data.IntMap                     as IntMap import           Data.List                       (nub)+import           Data.List.Extra                 (indexMaybe) #if !MIN_VERSION_base(4,11,0) import           Data.Monoid #endif
src/Clash/Netlist/Util.hs view
@@ -37,6 +37,7 @@ import           Data.String             (fromString) import           Data.List               (intersperse, unzip4, intercalate) import qualified Data.List               as List+import qualified Data.List.Extra         as List import           Data.Maybe              (catMaybes,fromMaybe,isNothing) import           Data.Monoid             (First (..)) import           Text.Printf             (printf)@@ -68,13 +69,14 @@    extendInScopeIdList, mkSubst, substTm) import           Clash.Core.Term   (Alt, LetBinding, Pat (..), Term (..), TickInfo (..), NameMod (..),-   collectArgsTicks, collectTicks, PrimInfo(primName))+   collectArgsTicks, collectTicks, collectBndrs, PrimInfo(primName), mkTicks, stripTicks)+import           Clash.Core.TermInfo import           Clash.Core.TyCon   (TyConName, TyConMap, tyConDataCons) import           Clash.Core.Type         (Type (..), TypeView (..),                                           coreView1, splitTyConAppM, tyView, TyVar) import           Clash.Core.Util-  (collectBndrs, stripTicks, substArgTys, termType, tyLitShow, mkTicks)+  (substArgTys, tyLitShow) import           Clash.Core.Var   (Id, Var (..), mkLocalId, modifyVarName, Attr') import           Clash.Core.VarEnv@@ -630,10 +632,12 @@   -> PortName filterVoidPorts _hwty (PortName s) =   PortName s-filterVoidPorts (FilteredHWType _hwty [filtered]) (PortProduct s ps) =-  PortProduct s [filterVoidPorts f p | (p, (void, f)) <- zip ps filtered, not void]+filterVoidPorts (FilteredHWType _hwty [filtered]) (PortProduct s ps)+  | length filtered > 1+  = PortProduct s [filterVoidPorts f p | (p, (void, f)) <- zip ps filtered, not void] filterVoidPorts (FilteredHWType _hwty fs) (PortProduct s ps)   | length (filter (not.fst) (concat fs)) == 1+  , length fs > 1   , length ps == 2   = PortProduct s ps filterVoidPorts filtered pp@(PortProduct _s _ps) =@@ -691,7 +695,7 @@       let resRead = any (localIdOccursIn res) exprs       -- Rename some of the binders, see 'setBinderName' when this happens.       ((res2,subst1,extraBndr),bndrs1) <--        mapAccumLM (setBinderName substRes res resRead) (res1,substRes,[]) binds+        List.mapAccumLM (setBinderName substRes res resRead) (res1,substRes,[]) binds       -- Make let-binders unique, the result binder is already unique, so we       -- can skip it.       let (bndrsL,r:bndrsR) = break ((== res2)) bndrs1@@ -1385,7 +1389,7 @@                         (extendPorts . t_inputs)                         annM   arguments <- zipWithM appendIdentifier (map (\a -> ("input",snd a)) args) [0..]-  (_,arguments1) <- mapAccumLM (\acc (p,i) -> mkTopInput topM acc p i)+  (_,arguments1) <- List.mapAccumLM (\acc (p,i) -> mkTopInput topM acc p i)                       (zip inNames inTys)                       (zip iPortSupply arguments)   let (iports,wrappers,idsI) = unzip3 arguments1@@ -1506,7 +1510,7 @@       case hwty' of         Vector sz hwty'' -> do           arguments <- mapM (appendIdentifier (i',hwty'')) [0..sz-1]-          (inps'',arguments1) <- mapAccumLM go inps' arguments+          (inps'',arguments1) <- List.mapAccumLM go inps' arguments           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids                           [ Identifier i' (Just (Indexed (hwty,10,n)))@@ -1518,7 +1522,7 @@          RTree d hwty'' -> do           arguments <- mapM (appendIdentifier (i',hwty'')) [0..2^d-1]-          (inps'',arguments1) <- mapAccumLM go inps' arguments+          (inps'',arguments1) <- List.mapAccumLM go inps' arguments           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids                           [ Identifier i' (Just (Indexed (hwty,10,n)))@@ -1530,7 +1534,7 @@          Product _ _ hwtys -> do           arguments <- zipWithM appendIdentifier (map (i,) hwtys) [0..]-          (inps'',arguments1) <- mapAccumLM go inps' arguments+          (inps'',arguments1) <- List.mapAccumLM go inps' arguments           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids                           [ Identifier i' (Just (Indexed (hwty,0,n)))@@ -1562,7 +1566,7 @@         Vector sz hwty'' -> do           arguments <- mapM (appendIdentifier (pN',hwty'')) [0..sz-1]           (inps'',arguments1) <--            mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'+            List.mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'                        (zip (extendPorts ps) arguments)           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids@@ -1576,7 +1580,7 @@         RTree d hwty'' -> do           arguments <- mapM (appendIdentifier (pN',hwty'')) [0..2^d-1]           (inps'',arguments1) <--            mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'+            List.mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'                        (zip (extendPorts ps) arguments)           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids@@ -1590,7 +1594,7 @@         Product _ _ hwtys -> do           arguments <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]           (inps'',arguments1) <--            mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'+            List.mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'                        (zip (extendPorts ps) arguments)           let (ports,decls,ids) = unzip3 arguments1               assigns = zipWith (argBV topM) ids@@ -1605,7 +1609,7 @@           let hwtys = [BitVector (conSize hwty'),elTy]           arguments <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]           (inps'',arguments1) <--            mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'+            List.mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'                        (zip (extendPorts ps) arguments)           let (ports,decls,ids) = unzip3 arguments1           case ids of@@ -1700,7 +1704,7 @@       case hwty' of         Vector sz hwty'' -> do           results <- mapM (appendIdentifier (o',hwty'')) [0..sz-1]-          (outps'',results1) <- mapAccumLM go outps' results+          (outps'',results1) <- List.mapAccumLM go outps' results           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids               netassgn = Assignment o' (mkVectorChain sz hwty'' ids')@@ -1711,7 +1715,7 @@          RTree d hwty'' -> do           results <- mapM (appendIdentifier (o',hwty'')) [0..2^d-1]-          (outps'',results1) <- mapAccumLM go outps' results+          (outps'',results1) <- List.mapAccumLM go outps' results           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids               netassgn = Assignment o' (mkRTreeChain d hwty'' ids')@@ -1722,7 +1726,7 @@          Product _ _ hwtys -> do           results <- zipWithM appendIdentifier (map (o',) hwtys) [0..]-          (outps'',results1) <- mapAccumLM go outps' results+          (outps'',results1) <- List.mapAccumLM go outps' results           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids               netassgn = Assignment o' (DataCon hwty (DC (hwty,0)) ids')@@ -1753,7 +1757,7 @@         Vector sz hwty'' -> do           results <- mapM (appendIdentifier (pN',hwty'')) [0..sz-1]           (outps'',results1) <--            mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'+            List.mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'                        (zip (extendPorts ps) results)           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids@@ -1766,7 +1770,7 @@         RTree d hwty'' -> do           results <- mapM (appendIdentifier (pN',hwty'')) [0..2^d-1]           (outps'',results1) <--            mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'+            List.mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'                        (zip (extendPorts ps) results)           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids@@ -1779,7 +1783,7 @@         Product _ _ hwtys -> do           results <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]           (outps'',results1) <--            mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'+            List.mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'                        (zip (extendPorts ps) results)           let (ports,decls,ids) = unzip3 results1               ids' = map (resBV topM) ids@@ -1794,7 +1798,7 @@           let hwtys = [BitVector (conSize elTy),elTy]           results <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]           (outps'',results1) <--            mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'+            List.mapAccumLM (\acc (p',o') -> mkTopOutput' topM acc p' o') outps'                        (zip (extendPorts ps) results)           let (ports,decls,ids) = unzip3 results1               ids1 = map (resBV topM) ids
src/Clash/Normalize.hs view
@@ -42,17 +42,18 @@ import           Clash.Core.Pretty                (PrettyOptions(..), showPpr, showPpr', ppr) import           Clash.Core.Subst   (extendGblSubstList, mkSubst, substTm)-import           Clash.Core.Term                  (Term (..), collectArgsTicks)+import           Clash.Core.Term                  (Term (..), collectArgsTicks+                                                  ,mkApps, mkTicks) import           Clash.Core.Type                  (Type, splitCoreFunForallTy) import           Clash.Core.TyCon   (TyConMap, TyConName) import           Clash.Core.Type                  (isPolyTy)-import           Clash.Core.Util                  (mkApps, mkTicks) import           Clash.Core.Var                   (Id, varName, varType) import           Clash.Core.VarEnv   (VarEnv, elemVarSet, eltsVarEnv, emptyInScopeSet, emptyVarEnv,    extendVarEnv, lookupVarEnv, mapVarEnv, mapMaybeVarEnv,    mkVarEnv, mkVarSet, notElemVarEnv, notElemVarSet, nullVarEnv, unionVarEnv)+import           Clash.Debug                      (traceIf) import           Clash.Driver.Types   (BindingMap, Binding(..), ClashOpts (..), DebugLevel (..)) import           Clash.Netlist.Types@@ -62,7 +63,7 @@ import           Clash.Normalize.Strategy import           Clash.Normalize.Transformations   (appPropFast, bindConstantVar, caseCon, flattenLet, reduceConst, topLet,-   reduceNonRepPrim, removeUnusedExpr)+   reduceNonRepPrim, removeUnusedExpr, deadCode) import           Clash.Normalize.Types import           Clash.Normalize.Util import           Clash.Primitives.Types           (CompiledPrimMap)@@ -389,7 +390,7 @@       repeatR (topdownR (apply "appPropFast" appPropFast >->                  apply "bindConstantVar" bindConstantVar >->                  apply "caseCon" caseCon >->-                 apply "reduceConst" reduceConst >->+                 (apply "reduceConst" reduceConst !-> apply "deadcode" deadCode) >->                  apply "reduceNonRepPrim" reduceNonRepPrim >->                  apply "removeUnusedExpr" removeUnusedExpr >->                  apply "flattenLet" flattenLet)) !->
src/Clash/Normalize/DEC.hs view
@@ -47,6 +47,7 @@ import qualified Data.IntMap.Strict               as IM import qualified Data.IntSet                      as IntSet import qualified Data.List                        as List+import qualified Data.List.Extra                  as List import qualified Data.Map.Strict                  as Map import qualified Data.Maybe                       as Maybe import           Data.Monoid                      (All (..))@@ -59,10 +60,10 @@ import Clash.Core.Literal    (Literal (..)) import Clash.Core.Term   (LetBinding, Pat (..), PrimInfo (..), Term (..), TickInfo (..), collectArgs,-   collectArgsTicks)+   collectArgsTicks, mkApps, mkTicks, patIds)+import Clash.Core.TermInfo   (termType) import Clash.Core.TyCon      (tyConDataCons) import Clash.Core.Type       (Type, isPolyFunTy, mkTyConApp, splitFunForallTy)-import Clash.Core.Util       (mkApps, mkTicks, patIds, termType) import Clash.Core.Var        (isGlobalId) import Clash.Core.VarEnv   (InScopeSet, elemInScopeSet, notElemInScopeSet)@@ -218,7 +219,7 @@                   ,[(Term,([Term],CaseTree [(Either Term Type)]))]                   ) collectGlobalsArgs inScope substitution seen args = do-    (_,(args',collected)) <- second unzip <$> mapAccumLM go seen args+    (_,(args',collected)) <- second unzip <$> List.mapAccumLM go seen args     return (args',concat collected)   where     go s (Left tm) = do@@ -265,7 +266,7 @@                   ,[(Term,([Term],CaseTree [(Either Term Type)]))]                   ) collectGlobalsLbs inScope substitution seen lbs = do-    (_,(lbs',collected)) <- second unzip <$> mapAccumLM go seen lbs+    (_,(lbs',collected)) <- second unzip <$> List.mapAccumLM go seen lbs     return (lbs',concat collected)   where     go :: [Term] -> LetBinding@@ -339,7 +340,7 @@ disJointSelProj inScope argTys cs = do     let maxIndex = length argTys - 1         css = map (\i -> fmap ((:[]) . (!!i)) cs) [0..maxIndex]-    (untran,tran) <- partitionM (isUntranslatableType False . snd) (zip [0..] argTys)+    (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')                              untran untranCs@@ -457,9 +458,9 @@     Just t | t || anyArgNotConstant -> pure (Just e)     _ | DeDup `elem` ticks -> pure (Just e)     _ -> do-      let isInteresting = uncurry3 (interestingToLift inScope eval) . collectArgsTicks+      let isInteresting = (\(x, y, z) -> interestingToLift inScope eval x y z) . collectArgsTicks       if isHOTy (primType pInfo) then do-        anyInteresting <- anyM (fmap Maybe.isJust . isInteresting) lArgs+        anyInteresting <- List.anyM (fmap Maybe.isJust . isInteresting) lArgs         if anyInteresting then pure (Just e) else pure Nothing       else         pure Nothing
src/Clash/Normalize/PrimitiveReductions.hs view
@@ -49,7 +49,8 @@ import           Clash.Core.Pretty                (showPpr) import           Clash.Core.Term   (CoreContext (..), PrimInfo (..), Term (..), WorkInfo (..), Pat (..),-   collectTermIds)+   collectTermIds, mkApps, idToVar)+import           Clash.Core.TermInfo import           Clash.Core.Type                  (LitTy (..), Type (..),                                                    TypeView (..), coreView1,                                                    mkFunTy, mkTyConApp,@@ -58,8 +59,8 @@   (TyConMap, TyConName, tyConDataCons, tyConName) import           Clash.Core.TysPrim               (integerPrimTy, typeNatKind) import           Clash.Core.Util-  (appendToVec, extractElems, extractTElems, idToVar, mkApps, mkRTree,-   mkUniqInternalId, mkUniqSystemTyVar, mkVec, termType, dataConInstArgTys,+  (appendToVec, extractElems, extractTElems, mkRTree,+   mkUniqInternalId, mkUniqSystemTyVar, mkVec, dataConInstArgTys,    primCo, undefinedTm) import           Clash.Core.Var                   (Var (..)) import           Clash.Core.VarEnv
src/Clash/Normalize/Transformations.hs view
@@ -72,20 +72,21 @@ import qualified Data.Either                 as Either import qualified Data.HashMap.Lazy           as HashMap import qualified Data.HashMap.Strict         as HashMapS-import qualified Data.List                   as List import           Data.List                   ((\\))+import qualified Data.List                   as List+import qualified Data.List.Extra             as List import qualified Data.Maybe                  as Maybe import qualified Data.Monoid                 as Monoid import qualified Data.Primitive.ByteArray    as BA import qualified Data.Text                   as Text import qualified Data.Vector.Primitive       as PV-import           Debug.Trace import           GHC.Integer.GMP.Internals   (Integer (..), BigNat (..))  import           BasicTypes                  (InlineSpec (..))  import           Clash.Annotations.Primitive (extractPrim) import           Clash.Core.DataCon          (DataCon (..))+import           Clash.Core.EqSolver import           Clash.Core.Name   (Name (..), NameSort (..), mkUnsafeSystemName, nameOcc) import           Clash.Core.FreeVars@@ -95,15 +96,8 @@ import           Clash.Core.Literal          (Literal (..)) import           Clash.Core.Pretty           (showPpr) import           Clash.Core.Subst-  (Subst, substTm, mkSubst, extendIdSubst, extendIdSubstList, extendTvSubst,-   extendTvSubstList, freshenTm, substTyInVar, deShadowTerm, deShadowAlt,-   deshadowLetExpr) import           Clash.Core.Term-  ( LetBinding, Pat (..), Term (..), CoreContext (..), PrimInfo (..)-  , TickInfo(..) , WorkInfo(WorkConstant), Alt, TickInfo-  , isLambdaBodyCtx, isTickCtx, collectArgs-  , collectArgsTicks, collectTicks , partitionTicks-  )+import           Clash.Core.TermInfo import           Clash.Core.Type             (Type (..), TypeView (..), applyFunTy,                                               isPolyFunCoreTy, isClassTy,                                               normalizeType, splitFunForallTy,@@ -112,10 +106,7 @@                                               LitTy (..), coreView1) import           Clash.Core.TyCon            (TyConMap, tyConDataCons) import           Clash.Core.Util-  (isCon, isFun, isLet, isPolyFun, isPrim,-   isSignalType, isVar, mkApps, mkLams, mkVec, piResultTy, termSize, termType,-   tyNatSize, patVars, isAbsurdAlt, altEqs, substInExistentialsList,-   solveNonAbsurds, patIds, isLocalVar, undefinedTm, stripTicks, mkTicks,+  ( isSignalType, mkVec, tyNatSize, undefinedTm,    shouldSplit, inverseTopSortLetBindings) import           Clash.Core.Var   (Id, TyVar, Var (..), isGlobalId, isLocalId, mkLocalId)@@ -126,6 +117,7 @@    unitVarSet, mkVarSet, mkInScopeSet, uniqAway, elemInScopeSet, elemVarEnv,    foldlWithUniqueVarEnv', lookupVarEnvDirectly, extendVarEnv, unionVarEnv,    eltsVarEnv, mkVarEnv, eltsVarSet)+import           Clash.Debug import           Clash.Driver.Types          (Binding(..), DebugLevel (..)) import           Clash.Netlist.BlackBox.Types (Element(Err)) import           Clash.Netlist.BlackBox.Util (getUsedArguments)@@ -832,7 +824,7 @@       used    = List.foldl' collectUsed emptyVarEnv (eltsVarSet bodyFVs)   case eltsVarEnv used of     [] -> changed body-    qqL | neLength qqL binds+    qqL | not (List.equalLength qqL binds)         -> changed (Letrec qqL body)         | otherwise         -> return e@@ -1910,9 +1902,8 @@        -- Extract projection of this case statement. Subsequent calls to       -- 'stripProjection' will check if new target is actually used.-      n <- headMaybe fTrace1-      vTarget1 <- indexMaybe xs n-      fTrace2 <- tailMaybe fTrace1+      (n, fTrace2) <- List.uncons fTrace1+      vTarget1 <- List.indexMaybe xs n        stripProjection fTrace2 (Var vTarget1) r @@ -2081,9 +2072,9 @@         let [lhsElTy,rhsElty,resElTy,nTy] = Either.rights args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure (ultra || n < 2)+            shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx-                                 , anyM isUntranslatableType_not_poly+                                 , List.anyM isUntranslatableType_not_poly                                         [lhsElTy,rhsElty,resElTy] ]             if shouldReduce1                then let [fun,lhsArg,rhsArg] = Either.lefts args@@ -2095,9 +2086,9 @@         let [argElTy,resElTy,nTy] = Either.rights args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure (ultra || n < 2 )+            shouldReduce1 <- List.orM [ pure (ultra || n < 2 )                                  , shouldReduce ctx-                                 , anyM isUntranslatableType_not_poly+                                 , List.anyM isUntranslatableType_not_poly                                         [argElTy,resElTy] ]             if shouldReduce1                then let [fun,arg] = Either.lefts args@@ -2115,7 +2106,7 @@         let [aTy,nTy] = Either.rights args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure (ultra || n == 0)+            shouldReduce1 <- List.orM [ pure (ultra || n == 0)                                  , shouldReduce ctx                                  , isUntranslatableType_not_poly aTy ]             if shouldReduce1 then@@ -2127,9 +2118,9 @@         let [aTy,bTy,nTy] = Either.rights args         in  case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure ultra+            shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx-                                 , anyM isUntranslatableType_not_poly [aTy,bTy] ]+                                 , List.anyM isUntranslatableType_not_poly [aTy,bTy] ]             if shouldReduce1               then let [fun,start,arg] = Either.lefts args                    in  (`mkTicks` ticks) <$> reduceFoldr c n aTy fun start arg@@ -2148,7 +2139,7 @@                 | n == 0 -> changed rArg                 | m == 0 -> changed lArg                 | otherwise -> do-                    shouldReduce1 <- orM [ shouldReduce ctx+                    shouldReduce1 <- List.orM [ shouldReduce ctx                                          , isUntranslatableType_not_poly aTy ]                     if shouldReduce1                        then (`mkTicks` ticks) <$> reduceAppend is0 n m aTy lArg rArg@@ -2159,7 +2150,7 @@             [vArg]    = Either.lefts args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceHead is0 (n+1) aTy vArg@@ -2170,7 +2161,7 @@             [vArg]    = Either.lefts args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceTail is0 (n+1) aTy vArg@@ -2181,7 +2172,7 @@             [vArg]    = Either.lefts args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  ]             if shouldReduce1@@ -2193,7 +2184,7 @@             [vArg]    = Either.lefts args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceInit is0 (n+1) aTy vArg@@ -2213,7 +2204,7 @@         let ([_sArg,vArg],[nTy,aTy]) = Either.partitionEithers args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  ]             if shouldReduce1@@ -2225,7 +2216,7 @@         let ([_knArg,vArg,iArg,aArg],[nTy,aTy]) = Either.partitionEithers args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure ultra+            shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  ]@@ -2238,7 +2229,7 @@         let ([_knArg,vArg,iArg],[nTy,aTy]) = Either.partitionEithers args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure ultra+            shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx                                  , isUntranslatableType_not_poly aTy ]             if shouldReduce1@@ -2250,9 +2241,9 @@         let [nTy,argElTy,resElTy] = Either.rights args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ pure (ultra || n < 2)+            shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx-                                 , anyM isUntranslatableType_not_poly [argElTy,resElTy] ]+                                 , List.anyM isUntranslatableType_not_poly [argElTy,resElTy] ]             if shouldReduce1                then let [_,fun,arg] = Either.lefts args                     in  (`mkTicks` ticks) <$> reduceImap c n argElTy resElTy fun arg@@ -2279,7 +2270,7 @@         let ([_sArg,vArg],[nTy,aTy]) = Either.partitionEithers args         case runExcept (tyNatSize tcm nTy) of           Right n -> do-            shouldReduce1 <- orM [ shouldReduce ctx+            shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType False aTy ]             if shouldReduce1                then (`mkTicks` ticks) <$> reduceTReplicate n aTy eTy vArg@@ -2617,7 +2608,7 @@                    freeLocalIds (unionVarEnvWith (+))                    emptyVarEnv (`unitVarEnv` (1 :: Int))                    body-  (is2,binds1) <- second concat <$> mapAccumLM go is1 binds+  (is2,binds1) <- second concat <$> List.mapAccumLM go is1 binds   case binds1 of     -- inline binders into the body when there's only a single binder, and only     -- if that binder doesn't perform any work or is only used once in the body@@ -2788,7 +2779,7 @@   runXOpt <- Lens.view aggressiveXOpt    if runXOpt then do-    defPart <- partitionM (isPrimError . snd) alts+    defPart <- List.partitionM (isPrimError . snd) alts      case defPart of       ([], _)    -> return e
src/Clash/Normalize/Util.hs view
@@ -38,6 +38,7 @@ import           Data.Bifunctor          (bimap) import           Data.Either             (lefts) import qualified Data.List               as List+import qualified Data.List.Extra         as List import qualified Data.Map                as Map import qualified Data.HashMap.Strict     as HashMapS import           Data.Text               (Text)@@ -55,18 +56,18 @@   (deShadowTerm, extendTvSubst, extendTvSubstList, mkSubst, substTm, substTy,    substId, extendIdSubst) import           Clash.Core.Term-  (Context, CoreContext(AppArg), PrimInfo (..), Term (..), WorkInfo (..),-   TickInfo(NameMod), NameMod(PrefixName), collectArgs, collectArgsTicks)+import           Clash.Core.TermInfo     (isPolyFun, termType) import           Clash.Core.TyCon        (TyConMap) import           Clash.Core.Type   (Type(LitTy, VarTy), LitTy(SymTy), TypeView (..), tyView, undefinedTy,    splitFunForallTy, splitTyConAppM, mkPolyFunTy) import           Clash.Core.Util-  (isClockOrReset, isPolyFun, termType, mkApps, mkTicks)+  (isClockOrReset) import           Clash.Core.Var          (Id, TyVar, Var (..), isGlobalId) import           Clash.Core.VarEnv   (VarEnv, emptyInScopeSet, emptyVarEnv, extendVarEnv, extendVarEnvWith,    lookupVarEnv, unionVarEnvWith, unitVarEnv, extendInScopeSetList)+import           Clash.Debug             (traceIf) import           Clash.Driver.Types      (BindingMap, Binding(..), DebugLevel (..)) import {-# SOURCE #-} Clash.Normalize.Strategy (normalization) import           Clash.Normalize.Types@@ -77,8 +78,7 @@ import           Clash.Rewrite.Util   (runRewrite, specialise, mkTmBinderFor, mkDerivedName) import           Clash.Unique-import           Clash.Util-  (SrcSpan, anyM, makeCachedU, traceIf, mapAccumLM)+import           Clash.Util              (SrcSpan, makeCachedU)  -- | Determine if argument should reduce to a constant given a primitive and -- an argument number. Caches results.@@ -117,7 +117,7 @@   :: Context   -- ^ ..in the current transformcontext   -> RewriteMonad NormalizeState Bool-shouldReduce = anyM isConstantArg'+shouldReduce = List.anyM isConstantArg'   where     isConstantArg' (AppArg (Just (nm, _, i))) = isConstantArg nm i     isConstantArg' _ = pure False@@ -231,7 +231,7 @@   -- ^ Subterms   -> RewriteMonad NormalizeState ConstantSpecInfo mergeCsrs ctx ticks oldTerm proposedTerm subTerms = do-  subCsrs <- snd <$> mapAccumLM constantSpecInfoFolder ctx subTerms+  subCsrs <- snd <$> List.mapAccumLM constantSpecInfoFolder ctx subTerms    -- If any arguments are constant (and hence can be constant specced), a new   -- term is created with these constants left in, but variable parts let-bound.
src/Clash/Rewrite/Combinators.hs view
@@ -26,8 +26,7 @@ import qualified Control.Monad.Writer        as Writer import qualified Data.Monoid                 as Monoid -import           Clash.Core.Term             (Term (..), CoreContext (..), primArg)-import           Clash.Core.Util             (patIds)+import           Clash.Core.Term             (Term (..), CoreContext (..), primArg, patIds) import           Clash.Core.VarEnv   (extendInScopeSet, extendInScopeSetList) import           Clash.Rewrite.Types
src/Clash/Rewrite/Util.hs view
@@ -36,6 +36,7 @@ import           Data.Coerce                 (coerce) import           Data.Functor.Const          (Const (..)) import           Data.List                   (group, partition, sort)+import           Data.List.Extra             (allM, partitionM) import qualified Data.Map                    as Map import           Data.Maybe                  (catMaybes,isJust,mapMaybe) import qualified Data.Monoid                 as Monoid@@ -66,8 +67,7 @@ import           Clash.Core.Subst   (substTmEnv, aeqTerm, aeqType, extendIdSubst, mkSubst, substTm) import           Clash.Core.Term-  (LetBinding, Pat (..), Term (..), CoreContext (..), Context, PrimInfo (..),-   TmName, WorkInfo (..), TickInfo, collectArgs, collectArgsTicks)+import           Clash.Core.TermInfo import           Clash.Core.TyCon   (TyConMap, tyConDataCons) import           Clash.Core.Type             (KindOrType, Type (..),@@ -75,14 +75,13 @@                                               normalizeType,                                               typeKind, tyView, isPolyFunTy) import           Clash.Core.Util-  (isPolyFun, mkAbstraction, mkApps, mkLams, mkTicks,-   mkTmApps, mkTyApps, mkTyLams, termType, dataConInstArgTysE, isClockOrReset,-   isEnable, piResultTy)+  (dataConInstArgTysE, isClockOrReset, isEnable) import           Clash.Core.Var   (Id, IdScope (..), TyVar, Var (..), isLocalId, mkGlobalId, mkLocalId, mkTyVar) import           Clash.Core.VarEnv   (InScopeSet, VarEnv, elemVarSet, extendInScopeSetList, mkInScopeSet,    uniqAway, uniqAway', mapVarEnv)+import           Clash.Debug (traceIf) import           Clash.Driver.Types   (DebugLevel (..), BindingMap, Binding(..)) import           Clash.Netlist.Util          (representableType)
src/Clash/Util.hs view
@@ -24,26 +24,25 @@   ) where -import Control.Applicative            as X (Applicative,(<$>),(<*>),pure) import Control.Arrow                  as X ((***),(&&&),first,second) import qualified Control.Exception    as Exception+import Control.Lens import Control.Monad                  as X ((<=<),(>=>))-import Control.Monad.State            (MonadState,State,StateT,runState)+import Control.Monad.State            (MonadState,StateT) import qualified Control.Monad.State  as State-import Data.Typeable                  (Typeable) import Data.Function                  as X (on) import Data.Hashable                  (Hashable) import Data.HashMap.Lazy              (HashMap) import qualified Data.HashMap.Lazy    as HashMapL+import qualified Data.List.Extra      as List import Data.Maybe                     (fromMaybe, listToMaybe, catMaybes) import Data.Text.Prettyprint.Doc import Data.Text.Prettyprint.Doc.Render.String-import Data.Version                   (Version)-import qualified Data.Time.Format     as Clock-import qualified Data.Time.Clock      as Clock import Data.Time.Clock                (UTCTime)-import Control.Lens-import Debug.Trace                    (trace)+import qualified Data.Time.Clock      as Clock+import qualified Data.Time.Format     as Clock+import Data.Typeable                  (Typeable)+import Data.Version                   (Version) import GHC.Base                       (Int(..),isTrue#,(==#),(+#)) import GHC.Integer.Logarithms         (integerLogBase#) import qualified GHC.LanguageExtensions.Type as LangExt@@ -52,6 +51,8 @@ import qualified Language.Haskell.TH  as TH  import SrcLoc                         (SrcSpan, noSrcSpan)++import Clash.Debug import Clash.Unique  #ifdef CABAL@@ -117,7 +118,7 @@ pprTraceDebug   :: String -> Doc ann -> a -> a pprTraceDebug str doc x-  | debugIsOn = pprDebugAndThen trace (pretty str) doc x+  | debugIsOn = pprTrace str doc x   | otherwise = x  pprDebugAndThen@@ -179,31 +180,6 @@       l %= extendUniqMap key value       return value --- | Run a State-action using the State that is stored in a higher-layer Monad-liftState :: (MonadState s m)-          => Lens' s s' -- ^ Lens to the State in the higher-layer monad-          -> State s' a -- ^ The State-action to perform-          -> m a-liftState l m = do-  s <- use l-  let (a,s') = runState m s-  l .= s'-  return a---- | Functorial version of 'Control.Arrow.first'-firstM :: Functor f-       => (a -> f c)-       -> (a, b)-       -> f (c, b)-firstM f (x,y) = (,y) <$> f x---- | Functorial version of 'Control.Arrow.second'-secondM :: Functor f-        => (b -> f c)-        -> (a, b)-        -> f (a, c)-secondM f (x,y) = (x,) <$> f y- combineM :: (Applicative f)          => (a -> f b)          -> (c -> f d)@@ -211,64 +187,6 @@          -> f (b,d) combineM f g (x,y) = (,) <$> f x <*> g y --- | Performs trace when first argument evaluates to 'True'-traceIf :: Bool -> String -> a -> a-traceIf True  msg = trace msg-traceIf False _   = id-{-# INLINE traceIf #-}---- | A version of 'concatMap' that works with a monadic predicate.-concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]-concatMapM f as = concat <$> sequence (map f as)-{-# INLINE concatMapM #-}---- | Monadic version of 'Data.List.partition'-partitionM :: Monad m-           => (a -> m Bool)-           -> [a]-           -> m ([a], [a])-partitionM _ []     = return ([], [])-partitionM p (x:xs) = do-  test      <- p x-  (ys, ys') <- partitionM p xs-  return $ if test then (x:ys, ys') else (ys, x:ys')---- | Monadic version of 'Data.List.mapAccumL'-mapAccumLM :: (Monad m)-           => (acc -> x -> m (acc,y))-           -> acc-           -> [x]-           -> m (acc,[y])-mapAccumLM _ acc [] = return (acc,[])-mapAccumLM f acc (x:xs) = do-  (acc',y) <- f acc x-  (acc'',ys) <- mapAccumLM f acc' xs-  return (acc'',y:ys)---- | if-then-else as a function on an argument-ifThenElse :: (a -> Bool)-           -> (a -> b)-           -> (a -> b)-           -> a-           -> b-ifThenElse t f g a = if t a then f a else g a--infixr 5 <:>--- | Applicative version of 'GHC.Types.(:)'-(<:>) :: Applicative f-      => f a-      -> f [a]-      -> f [a]-x <:> xs = (:) <$> x <*> xs---- | Safe indexing, returns a 'Nothing' if the index does not exist-indexMaybe :: [a]-           -> Int-           -> Maybe a-indexMaybe [] _     = Nothing-indexMaybe (x:_)  0 = Just x-indexMaybe (_:xs) n = indexMaybe xs (n-1)- -- | Same as 'indexNote' with last two arguments swapped indexNote'   :: HasCallStack@@ -293,25 +211,7 @@   -- ^ Index /n/   -> a   -- ^ Error or element /n/-indexNote note = \xs i -> fromMaybe (error note) (indexMaybe xs i)---- | Safe version of 'head'-headMaybe :: [a] -> Maybe a-headMaybe (a:_) = Just a-headMaybe _ = Nothing---- | Safe version of 'tail'-tailMaybe :: [a] -> Maybe [a]-tailMaybe (_:as) = Just as-tailMaybe _ = Nothing---- | Split the second list at the length of the first list-splitAtList :: [b] -> [a] -> ([a], [a])-splitAtList [] xs         = ([], xs)-splitAtList _ xs@[]       = (xs, xs)-splitAtList (_:xs) (y:ys) = (y:ys', ys'')-    where-      (ys', ys'') = splitAtList xs ys+indexNote note = \xs i -> fromMaybe (error note) (List.indexMaybe xs i)  clashLibVersion :: Version #ifdef CABAL@@ -320,17 +220,6 @@ clashLibVersion = error "development version" #endif --- | Return number of occurrences of an item in a list-countEq-  :: Eq a-  => a-  --  ^ Needle-  -> [a]-  -- ^ Haystack-  -> Int-  -- ^ Times needle was found in haystack-countEq a as = length (filter (== a) as)- -- | \x y -> floor (logBase x y), x > 1 && y > 0 flogBase :: Integer -> Integer -> Maybe Int flogBase x y | x > 1 && y > 0 = Just (I# (integerLogBase# x y))@@ -348,69 +237,6 @@                 else Just (I# z1) clogBase _ _ = Nothing --- | Determine whether two lists are of equal length-equalLength-  :: [a] -> [b] -> Bool-equalLength [] [] = True-equalLength (_:as) (_:bs) = equalLength as bs-equalLength _ _ = False---- | Determine whether two lists are not of equal length-neLength-  :: [a] -> [b] -> Bool-neLength [] [] = False-neLength (_:as) (_:bs) = neLength as bs-neLength _ _ = True---- | Zip two lists of equal length------ NB Errors out for a DEBUG compiler when the two lists are not of equal length-zipEqual-  :: [a] -> [b] -> [(a,b)]-#if !defined(DEBUG)-zipEqual = zip-#else-zipEqual [] [] = []-zipEqual (a:as) (b:bs) = (a,b) : zipEqual as bs-zipEqual _ _ = error "zipEqual"-#endif---- | Is this a DEBUG compiler?-debugIsOn-  :: Bool-#if defined(DEBUG)-debugIsOn = True-#else-debugIsOn = False-#endif---- | Short-circuiting monadic version of 'any'-anyM-  :: (Monad m)-  => (a -> m Bool)-  -> [a]-  -> m Bool-anyM _ []     = return False-anyM p (x:xs) = do-  q <- p x-  if q then-    return True-  else-    anyM p xs---- | short-circuiting monadic version of 'or'-orM-  :: (Monad m)-  => [m Bool]-  -> m Bool-orM [] = pure False-orM (x:xs) = do-  p <- x-  if p then-    pure True-  else-    orM xs- -- | Get the package id of the type of a value -- >>> pkgIdFromTypeable (undefined :: TopEntity) -- "clash-prelude-0.99.3-64904d90747cb49e17166bbc86fec8678918e4ead3847193a395b258e680373c"@@ -430,29 +256,6 @@        | otherwise        = "%-S%03Qs" --- | Converts a curried function to a function on a triple-uncurry3-  :: (a -> b -> c -> d)-  -> (a,b,c)-  -> d-uncurry3 = \f (a,b,c) -> f a b c-{-# INLINE uncurry3 #-}--allM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool-allM _ [] = return True-allM p (x:xs) = do-  q <- p x-  if q then-    allM p xs-  else-    return False--traceWith :: (a -> String) -> a -> a-traceWith f a = trace (f a) a--traceShowWith :: Show b => (a -> b) -> a -> a-traceShowWith f a = trace (show (f a)) a- -- | Left-biased choice on maybes orElse :: Maybe a -> Maybe a -> Maybe a orElse x@(Just _) _y = x@@ -467,7 +270,7 @@ --  * compiling files with clash --  * running output tests with runghc --  * compiling (local) Template/Blackbox functions with Hint-wantedLanguageExtensions, unwantedLanguageExtensions :: [LangExt.Extension]+wantedLanguageExtensions :: [LangExt.Extension] wantedLanguageExtensions =   [ LangExt.BinaryLiterals   , LangExt.ConstraintKinds@@ -495,6 +298,7 @@ #endif   ] +unwantedLanguageExtensions :: [LangExt.Extension] unwantedLanguageExtensions =   [ LangExt.ImplicitPrelude   , LangExt.MonomorphismRestriction@@ -505,8 +309,3 @@   , LangExt.StrictData   ] -filterOnFst :: (a -> Bool) -> [(a, b)] -> [b]-filterOnFst f xs = map snd (filter (f . fst) xs)--filterOnSnd :: (b -> Bool) -> [(a, b)] -> [a]-filterOnSnd f xs = map fst (filter (f . snd) xs)
+ src/Data/List/Extra.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE CPP #-}++module Data.List.Extra where++import Control.Applicative (liftA2)++-- | Monadic version of 'Data.List.partition'+partitionM :: (Monad m) => (a -> m Bool) -> [a] -> m ([a], [a])+partitionM _ []     = return ([], [])+partitionM p (x:xs) = do+  test      <- p x+  (ys, ys') <- partitionM p xs+  return $ if test then (x:ys, ys') else (ys, x:ys')++-- | Monadic version of 'Data.List.mapAccumL'+mapAccumLM+  :: (Monad m)+  => (acc -> x -> m (acc,y))+  -> acc+  -> [x]+  -> m (acc,[y])+mapAccumLM _ acc [] = return (acc,[])+mapAccumLM f acc (x:xs) = do+  (acc',y) <- f acc x+  (acc'',ys) <- mapAccumLM f acc' xs+  return (acc'',y:ys)++infixr 5 <:>+-- | Applicative version of 'GHC.Types.(:)'+(<:>) :: Applicative f => f a -> f [a] -> f [a]+(<:>) = liftA2 (:)++-- | Safe indexing, returns a 'Nothing' if the index does not exist+indexMaybe :: [a] -> Int -> Maybe a+indexMaybe [] _     = Nothing+indexMaybe (x:_)  0 = Just x+indexMaybe (_:xs) n = indexMaybe xs (n-1)++splitAtList :: [b] -> [a] -> ([a], [a])+splitAtList [] xs         = ([], xs)+splitAtList _ xs@[]       = (xs, xs)+splitAtList (_:xs) (y:ys) = (y:ys', ys'')+    where+      (ys', ys'') = splitAtList xs ys++equalLength :: [a] -> [b] -> Bool+equalLength [] [] = True+equalLength (_:as) (_:bs) = equalLength as bs+equalLength _ _ = False++-- | Return number of occurrences of an item in a list+countEq+  :: Eq a+  => a+  --  ^ Needle+  -> [a]+  -- ^ Haystack+  -> Int+  -- ^ Times needle was found in haystack+countEq a as = length (filter (== a) as)++-- | Zip two lists of equal length+--+-- NB Errors out for a DEBUG compiler when the two lists are not of equal length+zipEqual+  :: [a] -> [b] -> [(a,b)]+#if !defined(DEBUG)+zipEqual = zip+#else+zipEqual [] [] = []+zipEqual (a:as) (b:bs) = (a,b) : zipEqual as bs+zipEqual _ _ = error "zipEqual"+#endif++-- | Short-circuiting monadic version of 'any'+anyM+  :: (Monad m)+  => (a -> m Bool)+  -> [a]+  -> m Bool+anyM _ []     = return False+anyM p (x:xs) = do+  q <- p x+  if q then+    return True+  else+    anyM p xs++allM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool+allM _ [] = return True+allM p (x:xs) = do+  q <- p x+  if q then+    allM p xs+  else+    return False++-- | short-circuiting monadic version of 'or'+orM+  :: (Monad m)+  => [m Bool]+  -> m Bool+orM [] = pure False+orM (x:xs) = do+  p <- x+  if p then+    pure True+  else+    orM xs+
src/Data/Semigroup/Monad/Extra.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+ {-# OPTIONS_GHC -Wno-orphans #-}  module Data.Semigroup.Monad.Extra@@ -6,8 +10,13 @@ where  import Control.Monad.Fix+import Control.Monad.State import Data.Semigroup.Monad  instance MonadFix f => MonadFix (Mon f) where   mfix f = Mon (mfix (getMon . f)) +instance MonadState s m => MonadState s (Mon m) where+  get = Mon get+  put = Mon . put+  state = Mon . state