module CLasH.Utils.Core.CoreTools where
import qualified Maybe
import qualified System.IO.Unsafe
import qualified Data.Map as Map
import qualified Data.Accessor.Monad.Trans.State as MonadState
import qualified GHC
import qualified Type
import qualified TcType
import qualified HsExpr
import qualified HsTypes
import qualified HscTypes
import qualified Name
import qualified Id
import qualified TyCon
import qualified DataCon
import qualified TysWiredIn
import qualified DynFlags
import qualified SrcLoc
import qualified CoreSyn
import qualified Var
import qualified IdInfo
import qualified VarSet
import qualified CoreUtils
import qualified CoreFVs
import qualified Literal
import qualified MkCore
import qualified VarEnv
import CLasH.Translator.TranslatorTypes
import CLasH.Utils.GhcTools
import CLasH.Utils.Core.BinderTools
import CLasH.Utils.HsTools
import CLasH.Utils.Pretty
import CLasH.Utils
import qualified CLasH.Utils.Core.BinderTools as BinderTools
type Binding = (CoreSyn.CoreBndr, CoreSyn.CoreExpr)
tfp_to_int :: Type.Type -> TypeSession Int
tfp_to_int ty = do
hscenv <- MonadState.get tsHscEnv
let norm_ty = normalize_tfp_int hscenv ty
case Type.splitTyConApp_maybe norm_ty of
Just (tycon, args) -> do
let name = Name.getOccString (TyCon.tyConName tycon)
case name of
"Dec" ->
tfp_to_int' ty
otherwise -> do
return $ error ("Callin tfp_to_int on non-dec:" ++ (show ty))
Nothing -> return $ error ("Callin tfp_to_int on non-dec:" ++ (show ty))
tfp_to_int' :: Type.Type -> TypeSession Int
tfp_to_int' ty = do
lens <- MonadState.get tsTfpInts
hscenv <- MonadState.get tsHscEnv
let norm_ty = normalize_tfp_int hscenv ty
let existing_len = Map.lookup (OrdType norm_ty) lens
case existing_len of
Just len -> return len
Nothing -> do
let new_len = eval_tfp_int hscenv ty
MonadState.modify tsTfpInts (Map.insert (OrdType norm_ty) (new_len))
return new_len
eval_tfp_int :: HscTypes.HscEnv -> Type.Type -> Int
eval_tfp_int env ty =
unsafeRunGhc libdir $ do
GHC.setSession env
setDynFlag DynFlags.Opt_ImplicitImportQualified
let from_int_t_name = mkRdrName "Types.Data.Num.Ops" "fromIntegerT"
let from_int_t = SrcLoc.noLoc $ HsExpr.HsVar from_int_t_name
let undef = hsTypedUndef $ coreToHsType ty
let app = SrcLoc.noLoc $ HsExpr.HsApp (from_int_t) (undef)
let int_ty = SrcLoc.noLoc $ HsTypes.HsTyVar TysWiredIn.intTyCon_RDR
let expr = HsExpr.ExprWithTySig app int_ty
core <- toCore expr
execCore core
where
libdir = DynFlags.topDir dynflags
dynflags = HscTypes.hsc_dflags env
normalize_tfp_int :: HscTypes.HscEnv -> Type.Type -> Type.Type
normalize_tfp_int env ty =
System.IO.Unsafe.unsafePerformIO $
normalizeType env ty
sized_word_len_ty :: Type.Type -> Type.Type
sized_word_len_ty ty = len
where
args = case Type.splitTyConApp_maybe ty of
Just (tycon, args) -> args
Nothing -> error $ "\nCoreTools.sized_word_len_ty: Not a sized word type: " ++ (pprString ty)
[len] = args
sized_int_len_ty :: Type.Type -> Type.Type
sized_int_len_ty ty = len
where
args = case Type.splitTyConApp_maybe ty of
Just (tycon, args) -> args
Nothing -> error $ "\nCoreTools.sized_int_len_ty: Not a sized int type: " ++ (pprString ty)
[len] = args
ranged_word_bound_ty :: Type.Type -> Type.Type
ranged_word_bound_ty ty = len
where
args = case Type.splitTyConApp_maybe ty of
Just (tycon, args) -> args
Nothing -> error $ "\nCoreTools.ranged_word_bound_ty: Not a sized word type: " ++ (pprString ty)
[len] = args
tfvec_len_ty :: Type.Type -> Type.Type
tfvec_len_ty ty = len
where
args = case Type.splitTyConApp_maybe ty of
Just (tycon, args) -> args
Nothing -> error $ "\nCoreTools.tfvec_len_ty: Not a vector type: " ++ (pprString ty)
[len, el_ty] = args
tfvec_elem :: Type.Type -> Type.Type
tfvec_elem ty = el_ty
where
args = case Type.splitTyConApp_maybe ty of
Just (tycon, args) -> args
Nothing -> error $ "\nCoreTools.tfvec_len: Not a vector type: " ++ (pprString ty)
[len, el_ty] = args
is_lam :: CoreSyn.CoreExpr -> Bool
is_lam (CoreSyn.Lam _ _) = True
is_lam _ = False
is_let :: CoreSyn.CoreExpr -> Bool
is_let (CoreSyn.Let _ _) = True
is_let _ = False
is_fun :: CoreSyn.CoreExpr -> Bool
is_fun (CoreSyn.Type _) = False
is_fun expr = (Type.isFunTy . CoreUtils.exprType) expr
is_poly :: CoreSyn.CoreExpr -> Bool
is_poly (CoreSyn.Type _) = False
is_poly expr = (Maybe.isJust . Type.splitForAllTy_maybe . CoreUtils.exprType) expr
is_var :: CoreSyn.CoreExpr -> Bool
is_var (CoreSyn.Var _) = True
is_var _ = False
is_lit :: CoreSyn.CoreExpr -> Bool
is_lit (CoreSyn.Lit _) = True
is_lit _ = False
is_applicable :: CoreSyn.CoreExpr -> Bool
is_applicable expr = is_fun expr || is_poly expr
is_simple :: CoreSyn.CoreExpr -> Bool
is_simple (CoreSyn.App _ _) = True
is_simple (CoreSyn.Var _) = True
is_simple (CoreSyn.Cast expr _) = is_simple expr
is_simple _ = False
has_free_tyvars :: CoreSyn.CoreExpr -> Bool
has_free_tyvars = not . VarSet.isEmptyVarSet . (CoreFVs.exprSomeFreeVars Var.isTyVar)
ty_has_free_tyvars :: Type.Type -> Bool
ty_has_free_tyvars = not . VarSet.isEmptyVarSet . Type.tyVarsOfType
has_free_vars :: CoreSyn.CoreExpr -> Bool
has_free_vars = not . VarSet.isEmptyVarSet . CoreFVs.exprFreeVars
expr_uses_binders :: [CoreSyn.CoreBndr] -> CoreSyn.CoreExpr -> Bool
expr_uses_binders bndrs = not . VarSet.isEmptyVarSet . (CoreFVs.exprSomeFreeVars (`elem` bndrs))
exprToVar :: CoreSyn.CoreExpr -> Var.Id
exprToVar (CoreSyn.Var id) = id
exprToVar expr = error $ "\nCoreTools.exprToVar: Not a var: " ++ show expr
exprToLit :: CoreSyn.CoreExpr -> Literal.Literal
exprToLit (CoreSyn.Lit lit) = lit
exprToLit expr = error $ "\nCoreTools.exprToLit: Not a lit: " ++ show expr
get_val_args :: Type.Type -> [CoreSyn.CoreExpr] -> [CoreSyn.CoreExpr]
get_val_args ty args = drop n args
where
(tyvars, predtypes, _) = TcType.tcSplitSigmaTy ty
n = length tyvars + length predtypes
getIntegerLiteral :: CoreSyn.CoreExpr -> TranslatorSession Integer
getIntegerLiteral expr =
case CoreSyn.collectArgs expr of
(CoreSyn.Var f, [CoreSyn.Lit (Literal.MachInt integer)])
| getFullString f == "GHC.Integer.smallInteger" -> return integer
(CoreSyn.Var f, [CoreSyn.Lit (Literal.MachInt64 integer)])
| getFullString f == "GHC.Integer.int64ToInteger" -> return integer
(CoreSyn.Var f, [CoreSyn.Lit (Literal.MachWord integer)])
| getFullString f == "GHC.Integer.wordToInteger" -> return integer
(CoreSyn.Var f, [CoreSyn.Lit (Literal.MachWord64 integer)])
| getFullString f == "GHC.Integer.word64ToInteger" -> return integer
(CoreSyn.Var f, [CoreSyn.Type dec_ty, dec_dict, CoreSyn.Type num_ty, num_dict, arg])
| getFullString f == "Types.Data.Num.Ops.fromIntegerT" -> do
int <- MonadState.lift tsType $ tfp_to_int dec_ty
return $ toInteger int
_ -> error $ "CoreTools.getIntegerLiteral: Unsupported Integer literal: " ++ pprString expr
reduceCoreListToHsList ::
[HscTypes.CoreModule]
-> CoreSyn.CoreExpr
-> TranslatorSession [CoreSyn.CoreExpr]
reduceCoreListToHsList cores app@(CoreSyn.App _ _) = do {
; let { (fun, args) = CoreSyn.collectArgs app
; len = length args
} ;
; case len of
3 -> do {
; let topelem = args!!1
; case (args!!2) of
(varz@(CoreSyn.Var id)) -> do {
; binds <- mapM (findExpr (isVarName id)) cores
; otherelems <- reduceCoreListToHsList cores (head (Maybe.catMaybes binds))
; return (topelem:otherelems)
}
(appz@(CoreSyn.App _ _)) -> do {
; otherelems <- reduceCoreListToHsList cores appz
; return (topelem:otherelems)
}
otherwise -> return [topelem]
}
otherwise -> return []
}
where
isVarName :: Monad m => Var.Var -> Var.Var -> m Bool
isVarName lookfor bind = return $ (Var.varName lookfor) == (Var.varName bind)
reduceCoreListToHsList _ _ = return []
isStateCon :: Var.Var -> Bool
isStateCon var =
case Id.idDetails var of
IdInfo.DataConWrapId dc ->
let tycon = DataCon.dataConTyCon dc
tyname = Name.getOccString tycon
dcname = Name.getOccString dc
in case (tyname, dcname) of
("State", "State") -> True
_ -> False
_ -> False
isStateType :: Type.Type -> Bool
isStateType ty | Just ty' <- Type.tcView ty = isStateType ty'
isStateType ty = Maybe.isJust $ do
(typef, _) <- Type.repSplitAppTy_maybe ty
(tycon, _) <- Type.splitTyConApp_maybe typef
if TyCon.isNewTyCon tycon && Name.getOccString tycon == "State"
then
Just ()
else
Nothing
hasStateType :: (TypedThing t) => t -> Bool
hasStateType expr = case getType expr of
Nothing -> False
Just ty -> isStateType ty
flattenLets ::
CoreSyn.CoreExpr
-> ([Binding], CoreSyn.CoreExpr)
flattenLets (CoreSyn.Let binds expr) =
(bindings ++ bindings', expr')
where
(bindings', expr') =flattenLets expr
bindings = CoreSyn.flattenBinds [binds]
flattenLets expr = ([], expr)
mkNonRecLets :: [Binding] -> CoreSyn.CoreExpr -> CoreSyn.CoreExpr
mkNonRecLets bindings expr = MkCore.mkCoreLets binds expr
where
binds = map (uncurry CoreSyn.NonRec) bindings
class TypedThing t where
getType :: t -> Maybe Type.Type
instance TypedThing CoreSyn.CoreExpr where
getType (CoreSyn.Type _) = Nothing
getType expr = Just $ CoreUtils.exprType expr
instance TypedThing CoreSyn.CoreBndr where
getType = return . Id.idType
instance TypedThing Type.Type where
getType = return . id
genUniques :: CoreSyn.CoreExpr -> TranslatorSession CoreSyn.CoreExpr
genUniques = genUniques' VarEnv.emptyVarEnv
genUniques' :: VarEnv.VarEnv CoreSyn.CoreBndr -> CoreSyn.CoreExpr -> TranslatorSession CoreSyn.CoreExpr
genUniques' subst (CoreSyn.Var f) = do
let f' = VarEnv.lookupWithDefaultVarEnv subst f f
return (CoreSyn.Var f')
genUniques' subst (CoreSyn.Lit l) = return $ CoreSyn.Lit l
genUniques' subst (CoreSyn.App f arg) = do
f' <- genUniques' subst f
arg' <- genUniques' subst arg
return (CoreSyn.App f' arg')
genUniques' subst expr@(CoreSyn.Lam bndr res) | CoreSyn.isTyVar bndr = return expr
genUniques' subst (CoreSyn.Lam bndr res) = do
(subst', bndr') <- genUnique subst bndr
res' <- genUniques' subst' res
return (CoreSyn.Lam bndr' res')
genUniques' subst (CoreSyn.Let (CoreSyn.NonRec bndr bound) res) = do
(subst', bndr') <- genUnique subst bndr
bound' <- genUniques' subst' bound
res' <- genUniques' subst' res
return $ CoreSyn.Let (CoreSyn.NonRec bndr' bound') res'
genUniques' subst (CoreSyn.Let (CoreSyn.Rec binds) res) = do
(subst', bndrs') <- mapAccumLM genUnique subst (map fst binds)
bounds' <- mapM (genUniques' subst' . snd) binds
res' <- genUniques' subst' res
let binds' = zip bndrs' bounds'
return $ CoreSyn.Let (CoreSyn.Rec binds') res'
genUniques' subst (CoreSyn.Case scrut bndr ty alts) = do
scrut' <- genUniques' subst scrut
(subst', bndr') <- genUnique subst bndr
alts' <- mapM (doalt subst') alts
return $ CoreSyn.Case scrut' bndr' ty alts'
where
doalt subst (con, bndrs, expr) = do
(subst', bndrs') <- mapAccumLM genUnique subst bndrs
expr' <- genUniques' subst' expr
return (con, bndrs', expr')
genUniques' subst (CoreSyn.Cast expr coercion) = do
expr' <- genUniques' subst expr
return $ CoreSyn.Cast expr' coercion
genUniques' subst (CoreSyn.Note note expr) = do
expr' <- genUniques' subst expr
return $ CoreSyn.Note note expr'
genUniques' subst expr@(CoreSyn.Type _) = return expr
genUnique :: VarEnv.VarEnv CoreSyn.CoreBndr -> CoreSyn.CoreBndr -> TranslatorSession (VarEnv.VarEnv CoreSyn.CoreBndr, CoreSyn.CoreBndr)
genUnique subst bndr = do
bndr' <- BinderTools.cloneVar bndr
let subst' = VarEnv.extendVarEnv subst bndr bndr'
return (subst', bndr')
mkSelCase :: CoreSyn.CoreExpr -> Int -> TranslatorSession CoreSyn.CoreExpr
mkSelCase scrut i = do
let scrut_ty = CoreUtils.exprType scrut
case Type.splitTyConApp_maybe scrut_ty of
Just (tycon, tyargs) -> case TyCon.tyConDataCons tycon of
[datacon] -> do
let field_tys = DataCon.dataConInstOrigArgTys datacon tyargs
let wildbndrs = map MkCore.mkWildBinder field_tys
sel_bndr <- mkInternalVar "sel" (field_tys!!i)
let scrut_bndr = MkCore.mkWildBinder scrut_ty
let binders = take i wildbndrs ++ [sel_bndr] ++ drop (i+1) wildbndrs
return $ CoreSyn.Case scrut scrut_bndr scrut_ty [(CoreSyn.DataAlt datacon, binders, CoreSyn.Var sel_bndr)]
dcs -> error $ "CoreTools.mkSelCase: Scrutinee type must have exactly one datacon. Extracting element " ++ (show i) ++ " from '" ++ pprString scrut ++ "' Datacons: " ++ (show dcs) ++ " Type: " ++ (pprString scrut_ty)
Nothing -> error $ "CoreTools.mkSelCase: Creating extractor case, but scrutinee has no tycon? Extracting element " ++ (show i) ++ " from '" ++ pprString scrut ++ "'" ++ " Type: " ++ (pprString scrut_ty)