packages feed

futhark-0.16.4: src/Futhark/Internalise/Bindings.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
-- | Internalising bindings.
module Futhark.Internalise.Bindings
  (
    bindingParams
  , bindingLoopParams
  , bindingLambdaParams
  , stmPattern
  )
  where

import Control.Monad.State  hiding (mapM)
import Control.Monad.Reader hiding (mapM)

import qualified Data.Map.Strict as M

import Language.Futhark as E hiding (matchDims)
import qualified Futhark.IR.SOACS as I
import Futhark.MonadFreshNames
import Futhark.Internalise.Monad
import Futhark.Internalise.TypesValues
import Futhark.Util

bindingParams :: [E.TypeParam] -> [E.Pattern]
              -> ([I.FParam] -> [[I.FParam]] -> InternaliseM a)
              -> InternaliseM a
bindingParams tparams params m = do
  flattened_params <- mapM flattenPattern params
  let params_idents = concat flattened_params
  params_ts <-
    internaliseParamTypes $
    map (flip E.setAliases () . E.unInfo . E.identType) params_idents
  let num_param_idents = map length flattened_params
      num_param_ts = map (sum . map length) $ chunks num_param_idents params_ts

  let shape_params = [ I.Param v $ I.Prim I.int32 | E.TypeParamDim v _ <- tparams ]
      shape_subst = M.fromList [ (I.paramName p, [I.Var $ I.paramName p]) | p <- shape_params ]
  bindingFlatPattern params_idents (concat params_ts) $ \valueparams ->
    I.localScope (I.scopeOfFParams $ shape_params++concat valueparams) $
    substitutingVars shape_subst $ m shape_params $
    chunks num_param_ts (concat valueparams)

bindingLoopParams :: [E.TypeParam] -> E.Pattern
                  -> ([I.FParam] -> [I.FParam] -> InternaliseM a)
                  -> InternaliseM a
bindingLoopParams tparams pat m = do
  pat_idents <- flattenPattern pat
  pat_ts <- internaliseLoopParamType (E.patternStructType pat)

  let shape_params = [ I.Param v $ I.Prim I.int32 | E.TypeParamDim v _ <- tparams ]
      shape_subst = M.fromList [ (I.paramName p, [I.Var $ I.paramName p]) | p <- shape_params ]

  bindingFlatPattern pat_idents pat_ts $ \valueparams ->
    I.localScope (I.scopeOfFParams $ shape_params++concat valueparams) $
    substitutingVars shape_subst $ m shape_params $ concat valueparams

bindingLambdaParams :: [E.Pattern] -> [I.Type]
                    -> ([I.LParam] -> InternaliseM a)
                    -> InternaliseM a
bindingLambdaParams params ts m = do
  params_idents <- concat <$> mapM flattenPattern params

  bindingFlatPattern params_idents ts $ \params' ->
    I.localScope (I.scopeOfLParams $ concat params') $ m $ concat params'

processFlatPattern :: Show t => [E.Ident] -> [t]
                   -> InternaliseM ([[I.Param t]], VarSubstitutions)
processFlatPattern x y = processFlatPattern' [] x y
  where
    processFlatPattern' pat []       _  = do
      let (vs, substs) = unzip pat
          substs' = M.fromList substs
          idents = reverse vs
      return (idents, substs')

    processFlatPattern' pat (p:rest) ts = do
      (ps, subst, rest_ts) <- handleMapping ts <$> internaliseBindee p
      processFlatPattern' ((ps, (E.identName p, map (I.Var . I.paramName) subst)) : pat) rest rest_ts

    handleMapping ts [] =
      ([], [], ts)
    handleMapping ts (r:rs) =
        let (ps, reps, ts')    = handleMapping' ts r
            (pss, repss, ts'') = handleMapping ts' rs
        in (ps++pss, reps:repss, ts'')

    handleMapping' (t:ts) vname =
      let v' = I.Param vname t
      in ([v'], v', ts)
    handleMapping' [] _ =
      error $ "processFlatPattern: insufficient identifiers in pattern." ++ show (x, y)

    internaliseBindee :: E.Ident -> InternaliseM [VName]
    internaliseBindee bindee = do
      let name = E.identName bindee
      n <- internalisedTypeSize $ flip E.setAliases () $ E.unInfo $ E.identType bindee
      case n of
        1 -> return [name]
        _ -> replicateM n $ newVName $ baseString name

bindingFlatPattern :: Show t => [E.Ident] -> [t]
                   -> ([[I.Param t]] -> InternaliseM a)
                   -> InternaliseM a
bindingFlatPattern idents ts m = do
  (ps, substs) <- processFlatPattern idents ts
  local (\env -> env { envSubsts = substs `M.union` envSubsts env}) $
    m ps

-- | Flatten a pattern.  Returns a list of identifiers.  The
-- structural type of each identifier is returned separately.
flattenPattern :: MonadFreshNames m => E.Pattern -> m [E.Ident]
flattenPattern = flattenPattern'
  where flattenPattern' (E.PatternParens p _) =
          flattenPattern' p
        flattenPattern' (E.Wildcard t loc) = do
          name <- newVName "nameless"
          flattenPattern' $ E.Id name t loc
        flattenPattern' (E.Id v (Info t) loc) =
          return [E.Ident v (Info t) loc]
        -- XXX: treat empty tuples and records as bool.
        flattenPattern' (E.TuplePattern [] loc) =
          flattenPattern' (E.Wildcard (Info $ E.Scalar $ E.Prim E.Bool) loc)
        flattenPattern' (E.RecordPattern [] loc) =
          flattenPattern' (E.Wildcard (Info $ E.Scalar $ E.Prim E.Bool) loc)
        flattenPattern' (E.TuplePattern pats _) =
          concat <$> mapM flattenPattern' pats
        flattenPattern' (E.RecordPattern fs loc) =
          flattenPattern' $ E.TuplePattern (map snd $ sortFields $ M.fromList fs) loc
        flattenPattern' (E.PatternAscription p _ _) =
          flattenPattern' p
        flattenPattern' (E.PatternLit _ t loc) =
          flattenPattern' $ E.Wildcard t loc
        flattenPattern' (E.PatternConstr _ _ ps _) =
          concat <$> mapM flattenPattern' ps

stmPattern :: E.Pattern -> [I.Type]
           -> ([VName] -> InternaliseM a)
           -> InternaliseM a
stmPattern pat ts m = do
  pat' <- flattenPattern pat
  let addShapeStms l =
        m (map I.paramName $ concat l)
  bindingFlatPattern pat' ts addShapeStms