{-|
  Copyright  :  (C) 2012-2016, University of Twente,
                         2017, Google Inc.
  License    :  BSD2 (see the file LICENSE)
  Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>

  Types used in Normalize modules
-}

{-# LANGUAGE TemplateHaskell #-}

module Clash.Normalize.Types where

import Control.Monad.State.Strict (State)
import Data.Map                   (Map)
import Data.Set                   (Set)
import Data.Text                  (Text)

import Clash.Core.Term        (Term)
import Clash.Core.Type        (Type)
import Clash.Core.Var         (Id)
import Clash.Core.VarEnv      (VarEnv)
import Clash.Driver.Types     (BindingMap)
import Clash.Primitives.Types (CompiledPrimMap)
import Clash.Rewrite.Types    (Rewrite, RewriteMonad)
import Clash.Util

-- | State of the 'NormalizeMonad'
data NormalizeState
  = NormalizeState
  { NormalizeState -> BindingMap
_normalized          :: BindingMap
  -- ^ Global binders
  , NormalizeState -> Map (Id, Int, Either Term Type) Id
_specialisationCache :: Map (Id,Int,Either Term Type) Id
  -- ^ Cache of previously specialized functions:
  --
  -- * Key: (name of the original function, argument position, specialized term/type)
  --
  -- * Elem: (name of specialized function,type of specialized function)
  , NormalizeState -> VarEnv Int
_specialisationHistory :: VarEnv Int
  -- ^ Cache of how many times a function was specialized
  , NormalizeState -> Int
_specialisationLimit :: !Int
  -- ^ Number of time a function 'f' can be specialized
  , NormalizeState -> VarEnv (VarEnv Int)
_inlineHistory   :: VarEnv (VarEnv Int)
  -- ^ Cache of function where inlining took place:
  --
  -- * Key: function where inlining took place
  --
  -- * Elem: (functions which were inlined, number of times inlined)
  , NormalizeState -> Int
_inlineLimit     :: !Int
  -- ^ Number of times a function 'f' can be inlined in a function 'g'
  , NormalizeState -> Word
_inlineFunctionLimit :: !Word
  -- ^ Size of a function below which it is always inlined if it is not
  -- recursive
  , NormalizeState -> Word
_inlineConstantLimit :: !Word
  -- ^ Size of a constant below which it is always inlined; 0 = no limit
  , NormalizeState -> CompiledPrimMap
_primitives :: CompiledPrimMap
  -- ^ Primitive Definitions
  , NormalizeState -> Map Text (Set Int)
_primitiveArgs :: Map Text (Set Int)
  -- ^ Cache for looking up constantness of blackbox arguments
  , NormalizeState -> VarEnv Bool
_recursiveComponents :: VarEnv Bool
  -- ^ Map telling whether a components is recursively defined.
  --
  -- NB: there are only no mutually-recursive component, only self-recursive
  -- ones.
  , NormalizeState -> Bool
_newInlineStrategy :: Bool
  -- ^ Flattening stage should use the new (no-)inlining strategy
  , NormalizeState -> Bool
_normalizeUltra :: Bool
  -- ^ High-effort normalization session, trading performance improvement for
  -- potentially much longer compile times. Follows the 'Clash.Driver.opt_ultra'
  -- flag.
  , NormalizeState -> Word
_inlineWFCacheLimit :: !Word
  -- ^ At what size do we cache normalized work-free top-level binders.
  }

makeLenses ''NormalizeState


-- | State monad that stores specialisation and inlining information
type NormalizeMonad = State NormalizeState

-- | RewriteSession with extra Normalisation information
type NormalizeSession = RewriteMonad NormalizeState

-- | A 'Transform' action in the context of the 'RewriteMonad' and 'NormalizeMonad'
type NormRewrite = Rewrite NormalizeState

-- | Description of a @Term@ in terms of the type "components" the @Term@ has.
--
-- Is used as a performance/size metric.
data TermClassification
  = TermClassification
  { TermClassification -> Int
_function   :: !Int -- ^ Number of functions
  , TermClassification -> Int
_primitive  :: !Int -- ^ Number of primitives
  , TermClassification -> Int
_selection  :: !Int -- ^ Number of selections/multiplexers
  }
  deriving Int -> TermClassification -> ShowS
[TermClassification] -> ShowS
TermClassification -> String
(Int -> TermClassification -> ShowS)
-> (TermClassification -> String)
-> ([TermClassification] -> ShowS)
-> Show TermClassification
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TermClassification] -> ShowS
$cshowList :: [TermClassification] -> ShowS
show :: TermClassification -> String
$cshow :: TermClassification -> String
showsPrec :: Int -> TermClassification -> ShowS
$cshowsPrec :: Int -> TermClassification -> ShowS
Show

makeLenses ''TermClassification