clash-ghc-0.6.1: src-ghc/CLaSH/GHC/GenerateBindings.hs
module CLaSH.GHC.GenerateBindings
(generateBindings)
where
import Control.Lens ((%~),(&))
import Control.Monad.State (State)
import qualified Control.Monad.State as State
import Data.Either (lefts, rights)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
import Data.List (isSuffixOf)
import qualified Data.Set as Set
import qualified Data.Set.Lens as Lens
import Unbound.Generics.LocallyNameless (name2String, runFreshM, unembed)
import qualified BasicTypes as GHC
import qualified CoreSyn as GHC
import qualified DynFlags as GHC
import qualified TyCon as GHC
import qualified TysWiredIn as GHC
import CLaSH.Annotations.TopEntity (TopEntity)
import CLaSH.Core.FreeVars (termFreeIds)
import CLaSH.Core.Term (Term (..), TmName)
import CLaSH.Core.Type (Type, TypeView (..), coreView, mkFunTy, splitFunForallTy)
import CLaSH.Core.TyCon (TyCon, TyConName)
import CLaSH.Core.TysPrim (tysPrimMap)
import CLaSH.Core.Subst (substTms)
import CLaSH.Core.Util (mkLams, mkTyLams, termType)
import CLaSH.Core.Var (Var (..))
import CLaSH.Driver.Types (BindingMap)
import CLaSH.GHC.GHC2Core (GHC2CoreState, tyConMap, coreToId, coreToName, coreToTerm,
makeAllTyCons, qualfiedNameString, emptyGHC2CoreState)
import CLaSH.GHC.LoadModules (loadModules)
import CLaSH.Normalize.Util
import CLaSH.Primitives.Types (PrimMap)
import CLaSH.Rewrite.Util (mkInternalVar, mkSelectorCase)
import CLaSH.Util ((***),first)
generateBindings ::
PrimMap
-> String
-> Maybe (GHC.DynFlags)
-> IO (BindingMap,HashMap TyConName TyCon,IntMap TyConName,Maybe TopEntity)
generateBindings primMap modName dflagsM = do
(bindings,clsOps,unlocatable,fiEnvs,topEntM) <- loadModules modName dflagsM
let ((bindingsMap,clsVMap),tcMap) = State.runState (mkBindings primMap bindings clsOps unlocatable) emptyGHC2CoreState
(tcMap',tupTcCache) = mkTupTyCons tcMap
tcCache = makeAllTyCons tcMap' fiEnvs
allTcCache = tysPrimMap `HashMap.union` tcCache
clsMap = HashMap.map (\(ty,i) -> (ty,mkClassSelector allTcCache ty i)) clsVMap
allBindings = bindingsMap `HashMap.union` clsMap
droppedAndRetypedBindings = dropAndRetypeBindings allTcCache allBindings
return (droppedAndRetypedBindings,allTcCache,tupTcCache,topEntM)
dropAndRetypeBindings :: HashMap TyConName TyCon -> BindingMap -> BindingMap
dropAndRetypeBindings allTcCache allBindings = oBindings
where
topEntities = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf ".topEntity" $ name2String var)
allBindings
testInputs = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf ".testInput" $ name2String var)
allBindings
expectedOutputs = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf ".expectedOutput" $ name2String var)
allBindings
dropAndRetype d (t,_) = snd
$ retype allTcCache
([],lambdaDropPrep d t)
t
tBindings = case topEntities of
(topEntity:_) -> dropAndRetype allBindings topEntity
_ -> allBindings
iBindings = case testInputs of
(testInput:_) -> dropAndRetype tBindings testInput
_ -> tBindings
oBindings = case expectedOutputs of
(expectedOutput:_) -> dropAndRetype iBindings expectedOutput
_ -> iBindings
-- | clean up cast-removal mess
retype :: HashMap TyConName TyCon
-> ([TmName], BindingMap) -- (visited, bindings)
-> TmName -- top
-> ([TmName], BindingMap)
retype tcm (visited,bindings) current = (visited', HashMap.insert current (ty',tm') bindings')
where
(_,tm) = bindings HashMap.! current
used = Set.toList $ Lens.setOf termFreeIds tm
(visited',bindings') = foldl (retype tcm) (current:visited,bindings) (filter (`notElem` visited) used)
usedTys = map (fst . (bindings' HashMap.!)) used
usedVars = zipWith Var usedTys used
tm' = substTms (zip used usedVars) tm
ty' = runFreshM (termType tcm tm')
mkBindings :: PrimMap
-> [(GHC.CoreBndr, GHC.CoreExpr)] -- Binders
-> [(GHC.CoreBndr,Int)] -- Class operations
-> [GHC.CoreBndr] -- Unlocatable Expressions
-> State GHC2CoreState
( BindingMap
, HashMap TmName (Type,Int)
)
mkBindings primMap bindings clsOps unlocatable = do
bindingsList <- mapM (\(v,e) -> do
tm <- coreToTerm primMap unlocatable e
v' <- coreToId v
return (varName v', (unembed (varType v'), tm))
) bindings
clsOpList <- mapM (\(v,i) -> do
v' <- coreToId v
let ty = unembed $ varType v'
return (varName v', (ty,i))
) clsOps
return (HashMap.fromList bindingsList, HashMap.fromList clsOpList)
mkClassSelector :: HashMap TyConName TyCon
-> Type
-> Int
-> Term
mkClassSelector tcm ty sel = newExpr
where
((tvs,dictTy:_),_) = first (lefts *** rights)
$ first (span (\l -> case l of Left _ -> True
_ -> False))
$ splitFunForallTy ty
newExpr = case coreView tcm dictTy of
(TyConApp _ _) -> runFreshM $ flip State.evalStateT (0 :: Int) $ do
(dcId,dcVar) <- mkInternalVar "dict" dictTy
selE <- mkSelectorCase "mkClassSelector" tcm dcVar 1 sel
return (mkTyLams (mkLams selE [dcId]) tvs)
(FunTy arg res) -> runFreshM $ flip State.evalStateT (0 :: Int) $ do
(dcId,dcVar) <- mkInternalVar "dict" (mkFunTy arg res)
return (mkTyLams (mkLams dcVar [dcId]) tvs)
(OtherType oTy) -> runFreshM $ flip State.evalStateT (0 :: Int) $ do
(dcId,dcVar) <- mkInternalVar "dict" oTy
return (mkTyLams (mkLams dcVar [dcId]) tvs)
mkTupTyCons :: GHC2CoreState -> (GHC2CoreState,IntMap TyConName)
mkTupTyCons tcMap = (tcMap'',tupTcCache)
where
tupTyCons = map (GHC.tupleTyCon GHC.BoxedTuple) [2..62]
(tcNames,tcMap') = State.runState (mapM (\tc -> coreToName GHC.tyConName GHC.tyConUnique qualfiedNameString tc) tupTyCons) tcMap
tupTcCache = IM.fromList (zip [2..62] tcNames)
tupHM = HashMap.fromList (zip tcNames tupTyCons)
tcMap'' = tcMap' & tyConMap %~ (`HashMap.union` tupHM)