packages feed

ddc-core-flow-0.4.3.1: DDC/Core/Flow/Transform/Schedule/Nest.hs

module DDC.Core.Flow.Transform.Schedule.Nest
        ( -- * Insertion into a loop nest
          scheduleContext
        )
where
import DDC.Core.Flow.Procedure
import DDC.Core.Flow.Process
import DDC.Core.Flow.Exp
import DDC.Core.Flow.Transform.Schedule.Error
import DDC.Core.Flow.Prim
import DDC.Core.Flow.Compounds
import DDC.Core.Flow.Context

import Control.Arrow
import qualified Data.Map as Map

scheduleContext
    :: (Type Name -> Context  -> Either Error (Type Name))
    -> (FillMap -> Operator -> Either Error ([StmtStart], [StmtBody], [StmtEnd]))
    -> Context
    -> Either Error Nest

scheduleContext frate fop topctx
 = do   fills <- maybe (Left ErrorMultipleFills) Right
               $ pathsOfFills topctx

        let (starts', ends')  = allocAndTrunc fills

        (starts, nest, ends) <- go topctx
         
        return $ insertStarts (starts' ++ starts)
               $ insertEnds   (ends'   ++ ends)
               $ nest
 where
  fop' op
   = do fills <- maybe (Left ErrorMultipleFills) Right
               $ pathsOfFills topctx
        fop fills op


  go ctx
   = case ctx of
      ContextRate{}
       -> do (s1,bodies,e1) <- ops   ctx
             (s2,i2,    e2) <- inner ctx
             rate'          <- frate (contextRate ctx) ctx

             let nest = NestLoop
                      { nestRate  = rate'
                      , nestStart = []
                      , nestBody  = bodies
                      , nestInner = i2
                      , nestEnd   = [] }

             return ( s1 ++ s2
                    , nest
                    , e1 ++ e2)

      ContextSelect{}
       -> do (s1,bodies,e1) <- ops   ctx
             (s2,i2, e2) <- inner ctx

             rateOuter      <- frate (contextOuterRate ctx) ctx
             rateInner      <- frate (contextInnerRate ctx) ctx

             let nest = NestGuard
                      { nestOuterRate  = rateOuter
                      , nestInnerRate  = rateInner
                      , nestFlags      = contextFlags     ctx
                      , nestBody  = bodies
                      , nestInner = i2 }

             return ( s1 ++ s2
                    , nest
                    , e1 ++ e2)


      ContextSegment{}
       -> do (s1,bodies,e1) <- ops   ctx
             (s2,i2,    e2) <- inner ctx

             rateOuter      <- frate (contextOuterRate ctx) ctx
             rateInner      <- frate (contextInnerRate ctx) ctx


             let nest = NestSegment
                      { nestOuterRate  = rateOuter
                      , nestInnerRate  = rateInner
                      , nestLength     = contextLens      ctx
                      , nestBody  = bodies
                      , nestInner = i2 }

             return ( s1 ++ s2
                    , nest
                    , e1 ++ e2)

      ContextAppend{}
       -> do (s1,i1,e1)     <- go (contextInner1 ctx)
             (s2,i2,e2)     <- go (contextInner2 ctx)

             let nest = NestList
                      [ i1, i2 ]

             return ( s1 ++ s2
                    , nest
                    , e1 ++ e2)



  ops ctx
   = do outs <- mapM fop' (contextOps ctx)
        let (ss,bs,es) = unzip3 outs
        return (concat ss, concat bs, concat es)

  inner ctx
   = do outs <- mapM go  (contextInner ctx)
        let (ss,ins,es) = unzip3 outs
        return (concat ss, listNest ins, concat es)

  listNest []
   = NestEmpty
  listNest [n]
   = n
  listNest ns
   = NestList ns


allocAndTrunc :: FillMap -> ([StmtStart], [StmtEnd])
allocAndTrunc fills
 = concat *** concat
 $ unzip
 $ map go 
 $ Map.toList fills
 where
  go (k,(f,t))
   | isSimple f || isNone f
   = ([], [])
   | otherwise
   = let k' = getAccForPath fills f
         kk = maybe k id k'
         co = NameVarMod kk "count"

         s  | k == kk
            = [StartAcc
              { startAccName = co
              , startAccType = tNat
              , startAccExp  = xNat 0 } ]
            | otherwise
            = []

         e  = [EndVecTrunc
                k t
                (UName co) ]

     in  (s, e)


-------------------------------------------------------------------------------
-- | Insert starting statements in the given context.
insertStarts :: [StmtStart] -> Nest -> Nest
insertStarts starts' nest
 = case nest of
    NestList (n:ns)
     -> NestList (insertStarts starts' n : ns) 
    NestLoop{}
     -> nest { nestStart = nestStart nest ++ starts' }
    _
     -> nest

-------------------------------------------------------------------------------
-- | Insert ends statements in the given context.
insertEnds :: [StmtEnd] -> Nest -> Nest
insertEnds ends' nest
 = case nest of
    NestList ns
     | (r:rs) <- reverse ns
     -> NestList (reverse rs ++ [insertEnds ends' r])
    NestLoop{}
     -> nest { nestEnd = nestEnd nest ++ ends' }
    _
     -> nest