--Standard modules
import qualified Maybe
import qualified System.IO.Unsafe
+import qualified Data.Map as Map
-- GHC API
import qualified GHC
-- Local imports
import CLasH.Translator.TranslatorTypes
import CLasH.Utils.GhcTools
+import CLasH.Utils.Core.BinderTools
import CLasH.Utils.HsTools
import CLasH.Utils.Pretty
import CLasH.Utils
type Binding = (CoreSyn.CoreBndr, CoreSyn.CoreExpr)
-- | Evaluate a core Type representing type level int from the tfp
--- library to a real int.
+-- library to a real int. Checks if the type really is a Dec type and
+-- caches the results.
+tfp_to_int :: Type.Type -> TypeSession Int
+tfp_to_int ty = do
+ hscenv <- MonadState.get tsHscEnv
+ let norm_ty = normalise_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))
+
+-- | Evaluate a core Type representing type level int from the tfp
+-- library to a real int. Caches the results. Do not use directly, use
+-- tfp_to_int instead.
+tfp_to_int' :: Type.Type -> TypeSession Int
+tfp_to_int' ty = do
+ lens <- MonadState.get tsTfpInts
+ hscenv <- MonadState.get tsHscEnv
+ let norm_ty = normalise_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
+
+-- | Evaluate a core Type representing type level int from the tfp
+-- library to a real int. Do not use directly, use tfp_to_int instead.
eval_tfp_int :: HscTypes.HscEnv -> Type.Type -> Int
eval_tfp_int env ty =
unsafeRunGhc libdir $ do
-- binder.
let subst' = VarEnv.extendVarEnv subst bndr bndr'
return (subst', bndr')
+
+-- Create a "selector" case that selects the ith field from a datacon
+mkSelCase :: CoreSyn.CoreExpr -> Int -> TranslatorSession CoreSyn.CoreExpr
+mkSelCase scrut i = do
+ let scrut_ty = CoreUtils.exprType scrut
+ case Type.splitTyConApp_maybe scrut_ty of
+ -- The scrutinee should have a type constructor. We keep the type
+ -- arguments around so we can instantiate the field types below
+ Just (tycon, tyargs) -> case TyCon.tyConDataCons tycon of
+ -- The scrutinee type should have a single dataconstructor,
+ -- otherwise we can't construct a valid selector case.
+ [datacon] -> do
+ let field_tys = DataCon.dataConInstOrigArgTys datacon tyargs
+ -- Create a list of wild binders for the fields we don't want
+ let wildbndrs = map MkCore.mkWildBinder field_tys
+ -- Create a single binder for the field we want
+ sel_bndr <- mkInternalVar "sel" (field_tys!!i)
+ -- Create a wild binder for the scrutinee
+ let scrut_bndr = MkCore.mkWildBinder scrut_ty
+ -- Create the case expression
+ 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 ++ "'"