{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Clash.Core.VarEnv
(
VarEnv
, nullVarEnv
, lookupVarEnv
, lookupVarEnv'
, lookupVarEnvDirectly
, emptyVarEnv
, unitVarEnv
, mkVarEnv
, extendVarEnv
, extendVarEnvList
, extendVarEnvWith
, delVarEnv
, delVarEnvList
, unionVarEnv
, unionVarEnvWith
, mapVarEnv
, mapMaybeVarEnv
, foldlWithUniqueVarEnv'
, elemVarEnv
, notElemVarEnv
, eltsVarEnv
, VarSet
, emptyVarSet
, unitVarSet
, delVarSetByKey
, unionVarSet
, elemVarSet
, notElemVarSet
, mkVarSet
, eltsVarSet
, InScopeSet
, emptyInScopeSet
, lookupInScope
, mkInScopeSet
, extendInScopeSet
, extendInScopeSetList
, unionInScope
, elemInScopeSet
, notElemInScopeSet
, varSetInScope
, uniqAway
, uniqAway'
, RnEnv
, mkRnEnv
, rnTmBndr
, rnTyBndr
, rnTmBndrs
, rnTyBndrs
, rnOccLId
, rnOccRId
, rnOccLTy
, rnOccRTy
)
where
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)
import GHC.Generics
import Clash.Core.Pretty ()
import Clash.Core.Var
import Clash.Debug (debugIsOn)
import Clash.Unique
import Clash.Util
import Clash.Pretty
type VarEnv a = UniqMap a
emptyVarEnv
:: VarEnv a
emptyVarEnv = emptyUniqMap
unitVarEnv
:: Var b
-> a
-> VarEnv a
unitVarEnv = unitUniqMap
lookupVarEnv
:: Var b
-> VarEnv a
-> Maybe a
lookupVarEnv = lookupUniqMap
lookupVarEnvDirectly
:: Unique
-> VarEnv a
-> Maybe a
lookupVarEnvDirectly = lookupUniqMap
lookupVarEnv'
:: VarEnv a
-> Var b
-> a
lookupVarEnv' = lookupUniqMap'
delVarEnv
:: VarEnv a
-> Var b
-> VarEnv a
delVarEnv = delUniqMap
delVarEnvList
:: VarEnv a
-> [Var b]
-> VarEnv a
delVarEnvList = delListUniqMap
extendVarEnv
:: Var b
-> a
-> VarEnv a
-> VarEnv a
extendVarEnv = extendUniqMap
extendVarEnvWith
:: Var b
-> a
-> (a -> a -> a)
-> VarEnv a
-> VarEnv a
extendVarEnvWith = extendUniqMapWith
extendVarEnvList
:: VarEnv a
-> [(Var b, a)]
-> VarEnv a
extendVarEnvList = extendListUniqMap
nullVarEnv
:: VarEnv a
-> Bool
nullVarEnv = nullUniqMap
unionVarEnv
:: VarEnv a
-> VarEnv a
-> VarEnv a
unionVarEnv = unionUniqMap
unionVarEnvWith
:: (a -> a -> a)
-> VarEnv a
-> VarEnv a
-> VarEnv a
unionVarEnvWith = unionUniqMapWith
mkVarEnv
:: [(Var a,b)]
-> VarEnv b
mkVarEnv = listToUniqMap
mapVarEnv
:: (a -> b)
-> VarEnv a
-> VarEnv b
mapVarEnv = mapUniqMap
mapMaybeVarEnv
:: (a -> Maybe b)
-> VarEnv a
-> VarEnv b
mapMaybeVarEnv = mapMaybeUniqMap
foldlWithUniqueVarEnv'
:: (a -> Unique -> b -> a)
-> a
-> VarEnv b
-> a
foldlWithUniqueVarEnv' = foldlWithUnique'
eltsVarEnv
:: VarEnv a
-> [a]
eltsVarEnv = eltsUniqMap
elemVarEnv
:: Var a
-> VarEnv b
-> Bool
elemVarEnv = elemUniqMap
notElemVarEnv
:: Var a
-> VarEnv b
-> Bool
notElemVarEnv = notElemUniqMap
type VarSet = UniqSet (Var Any)
emptyVarSet
:: VarSet
emptyVarSet = emptyUniqSet
unitVarSet
:: Var a
-> VarSet
unitVarSet v = unitUniqSet (coerce v)
extendVarSet
:: VarSet
-> Var a
-> VarSet
extendVarSet env v = extendUniqSet env (coerce v)
unionVarSet
:: VarSet
-> VarSet
-> VarSet
unionVarSet = unionUniqSet
elemVarSet
:: Var a
-> VarSet
-> Bool
elemVarSet v = elemUniqSet (coerce v)
notElemVarSet
:: Var a
-> VarSet
-> Bool
notElemVarSet v = notElemUniqSet (coerce v)
subsetVarSet
:: VarSet
-> VarSet
-> Bool
subsetVarSet = subsetUniqSet
lookupVarSet
:: Var a
-> VarSet
-> Maybe (Var Any)
lookupVarSet = lookupUniqSet
delVarSetByKey
:: Unique
-> VarSet
-> VarSet
delVarSetByKey = delUniqSetDirectly
mkVarSet
:: [Var a]
-> VarSet
mkVarSet xs = mkUniqSet (coerce xs)
eltsVarSet
:: VarSet
-> [Var Any]
eltsVarSet = eltsUniqSet
data InScopeSet = InScopeSet VarSet {-# UNPACK #-} !Int
deriving (Generic, Binary)
instance ClashPretty InScopeSet where
clashPretty (InScopeSet s _) = clashPretty s
extendInScopeSet
:: InScopeSet
-> Var a
-> InScopeSet
extendInScopeSet (InScopeSet inScope n) v =
InScopeSet (extendVarSet inScope v) (n + 1)
extendInScopeSetList
:: InScopeSet
-> [Var a]
-> InScopeSet
extendInScopeSetList (InScopeSet inScope n) vs =
InScopeSet (List.foldl' extendVarSet inScope vs) (n + length vs)
unionInScope
:: InScopeSet
-> InScopeSet
-> InScopeSet
unionInScope (InScopeSet s1 _) (InScopeSet s2 n2)
= InScopeSet (s1 `unionVarSet` s2) n2
varSetInScope
:: VarSet
-> InScopeSet
-> Bool
varSetInScope vars (InScopeSet s1 _)
= vars `subsetVarSet` s1
lookupInScope
:: InScopeSet
-> Var a
-> Maybe (Var Any)
lookupInScope (InScopeSet s _) v = lookupVarSet v s
elemInScopeSet
:: Var a
-> InScopeSet
-> Bool
elemInScopeSet v (InScopeSet s _) = elemVarSet v s
notElemInScopeSet
:: Var a
-> InScopeSet
-> Bool
notElemInScopeSet v (InScopeSet s _) = notElemVarSet v s
mkInScopeSet
:: VarSet
-> InScopeSet
mkInScopeSet is = InScopeSet is 1
emptyInScopeSet
:: InScopeSet
emptyInScopeSet = mkInScopeSet emptyVarSet
uniqAway
:: (Uniquable a, ClashPretty a)
=> InScopeSet
-> a
-> a
uniqAway (InScopeSet set n) a =
uniqAway' (`elemUniqSetDirectly` set) n a
uniqAway'
:: (Uniquable a, ClashPretty a)
=> (Unique -> Bool)
-> Int
-> a
-> a
uniqAway' inScopeTest n u =
if inScopeTest (getUnique u) then
try 1
else
u
where
origUniq = getUnique u
try k
| debugIsOn && k > 1000
= pprPanic "uniqAway loop:" msg
| inScopeTest uniq
= try (k + 1)
| k > 3
= pprTraceDebug "uniqAway:" msg (setUnique u uniq)
| otherwise
= setUnique u uniq
where
msg = fromPretty k <+> "tries" <+> clashPretty u <+> fromPretty n
uniq = deriveUnique origUniq (n * k)
deriveUnique
:: Unique
-> Int
-> Unique
deriveUnique i delta = i + delta
data RnEnv
= RnEnv
{ rn_envLTy :: VarEnv TyVar
, rn_envLTm :: VarEnv Id
, rn_envRTy :: VarEnv TyVar
, rn_envRTm :: VarEnv Id
, rn_inScope :: InScopeSet
}
mkRnEnv
:: InScopeSet -> RnEnv
mkRnEnv vars
= RnEnv
{ rn_envLTy = emptyVarEnv
, rn_envLTm = emptyVarEnv
, rn_envRTy = emptyVarEnv
, rn_envRTm = emptyVarEnv
, rn_inScope = vars
}
rnOccLTy
:: RnEnv -> TyVar -> TyVar
rnOccLTy rn v = fromMaybe v (lookupVarEnv v (rn_envLTy rn))
rnOccRTy
:: RnEnv -> TyVar -> TyVar
rnOccRTy rn v = fromMaybe v (lookupVarEnv v (rn_envRTy rn))
rnTyBndr
:: RnEnv -> TyVar -> TyVar -> RnEnv
rnTyBndr rv@(RnEnv {rn_envLTy = lenv, rn_envRTy = renv, rn_inScope = inScope}) bL bR =
rv { rn_envLTy = extendVarEnv bL newB lenv
, rn_envRTy = extendVarEnv bR newB renv
, rn_inScope = extendInScopeSet inScope newB }
where
newB | not (bL `elemInScopeSet` inScope) = bL
| not (bR `elemInScopeSet` inScope) = bR
| otherwise = uniqAway inScope bL
rnTyBndrs
:: RnEnv -> [TyVar] -> [TyVar] -> RnEnv
rnTyBndrs env tvs1 tvs2 =
List.foldl' (\s (l,r) -> rnTyBndr s l r) env (List.zipEqual tvs1 tvs2)
rnOccLId
:: RnEnv -> Id -> Id
rnOccLId rn v = fromMaybe v (lookupVarEnv v (rn_envLTm rn))
rnOccRId
:: RnEnv -> Id -> Id
rnOccRId rn v = fromMaybe v (lookupVarEnv v (rn_envRTm rn))
rnTmBndr
:: RnEnv -> Id -> Id -> RnEnv
rnTmBndr rv@(RnEnv {rn_envLTm = lenv, rn_envRTm = renv, rn_inScope = inScope}) bL bR =
rv { rn_envLTm = extendVarEnv bL newB lenv
, rn_envRTm = extendVarEnv bR newB renv
, rn_inScope = extendInScopeSet inScope newB }
where
newB | not (bL `elemInScopeSet` inScope) = bL
| not (bR `elemInScopeSet` inScope) = bR
| otherwise = uniqAway inScope bL
rnTmBndrs
:: RnEnv -> [Id] -> [Id] -> RnEnv
rnTmBndrs env ids1 ids2 =
List.foldl' (\s (l,r) -> rnTmBndr s l r) env (List.zipEqual ids1 ids2)