{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} module Clash.Core.TermInfo where import Data.Maybe (fromMaybe) import Data.Text (isInfixOf) import GHC.Stack (HasCallStack) import Clash.Core.HasType import Clash.Core.Name import Clash.Core.Term import Clash.Core.TyCon (tyConDataCons, TyConMap) import Clash.Core.Type import Clash.Core.Var import Clash.Unique (lookupUniqMap) import Clash.Util.Interpolate as I termSize :: Term -> Word termSize (Var {}) = 1 termSize (Data {}) = 1 termSize (Literal {}) = 1 termSize (Prim {}) = 1 termSize (Lam _ e) = termSize e + 1 termSize (TyLam _ e) = termSize e termSize (App e1 e2) = termSize e1 + termSize e2 termSize (TyApp e _) = termSize e termSize (Cast e _ _) = termSize e termSize (Tick _ e) = termSize e termSize (Let (NonRec _ x) e) = termSize x + termSize e termSize (Let (Rec xs) e) = sum (bodySz:bndrSzs) where bndrSzs = map (termSize . snd) xs bodySz = termSize e termSize (Case subj _ alts) = sum (subjSz:altSzs) where subjSz = termSize subj altSzs = map (termSize . snd) alts multPrimErr :: PrimInfo -> String multPrimErr primInfo = [I.i| Internal error in multiPrimInfo': could not produce MultiPrimInfo. This probably means a multi result blackbox's result type was not a tuple. PrimInfo: #{primInfo} |] splitMultiPrimArgs :: HasCallStack => MultiPrimInfo -> [Either Term Type] -> ([Either Term Type], [Id]) splitMultiPrimArgs MultiPrimInfo{mpi_resultTypes} args0 = (args1, resArgs1) where resArgs1 = [id_ | Left (Var id_) <- resArgs0] (args1, resArgs0) = splitAt (length args0 - length mpi_resultTypes) args0 -- | Same as 'multiPrimInfo', but produced an error if it could not produce a -- 'MultiPrimInfo'. multiPrimInfo' :: HasCallStack => TyConMap -> PrimInfo -> MultiPrimInfo multiPrimInfo' tcm primInfo = fromMaybe (error (multPrimErr primInfo)) (multiPrimInfo tcm primInfo) -- | Produce 'MutliPrimInfo' for given primitive multiPrimInfo :: TyConMap -> PrimInfo -> Maybe MultiPrimInfo multiPrimInfo tcm primInfo | (_primArgs, primResTy) <- splitFunForallTy (primType primInfo) , TyConApp tupTcNm tupEls <- tyView primResTy -- XXX: Hardcoded for tuples , "GHC.Tuple.(," `isInfixOf` nameOcc tupTcNm , Just tupTc <- lookupUniqMap tupTcNm tcm , [tupDc] <- tyConDataCons tupTc = Just $ MultiPrimInfo { mpi_primInfo = primInfo , mpi_resultDc = tupDc , mpi_resultTypes = tupEls } multiPrimInfo _ _ = Nothing -- | Does a term have a function type? isFun :: TyConMap -> Term -> Bool isFun m t = isFunTy m (inferCoreTypeOf m t) -- | Does a term have a function or polymorphic type? isPolyFun :: TyConMap -> Term -> Bool isPolyFun m t = isPolyFunCoreTy m (inferCoreTypeOf m t) -- | Is a term a recursive let-binding? isLet :: Term -> Bool isLet Let{} = True isLet _ = False -- | Is a term a variable reference? isVar :: Term -> Bool isVar (Var {}) = True isVar _ = False isLocalVar :: Term -> Bool isLocalVar (Var v) = isLocalId v isLocalVar _ = False -- | Is a term a datatype constructor? isCon :: Term -> Bool isCon (Data {}) = True isCon _ = False -- | Is a term a primitive? isPrim :: Term -> Bool isPrim (Prim {}) = True isPrim _ = False -- | Is a term a tick? isTick :: Term -> Bool isTick Tick{} = True isTick _ = False -- | Is a term a cast? isCast :: Term -> Bool isCast (Cast {}) = True isCast _ = False