ddc-core-flow-0.4.1.1: DDC/Core/Flow/Transform/Schedule/Nest.hs
module DDC.Core.Flow.Transform.Schedule.Nest
( -- * Insertion into a loop nest
insertContext
, insertStarts
, insertBody
, insertEnds
-- * Rate predicates
, nestContainsRate
, nestContainsGuardedRate)
where
import DDC.Core.Flow.Procedure
import DDC.Core.Flow.Compounds
import DDC.Core.Flow.Prim
import DDC.Core.Flow.Exp
import Data.Monoid
-------------------------------------------------------------------------------
-- | Insert a skeleton context into a nest.
-- The new context doesn't contain any statements, it just provides
-- the infrastructure to execute statements at the new rate.
--
insertContext :: Nest -> Context -> Maybe Nest
-- Context already exists, don't bother.
insertContext nest context@ContextRate{}
| nestContainsRate nest (contextRate context)
= Just nest
-- Loop context at top level.
insertContext NestEmpty context@ContextRate{}
= Just $ nestOfContext context
-- Drop Selector Context ------------------------
-- Selector context goes at this level in the loop nest.
insertContext nest@NestLoop{} context@ContextSelect{}
| nestRate nest == contextOuterRate context
, Just starts <- startsForContext context
= Just $ nest
{ nestInner = nestInner nest <> nestOfContext context
, nestStart = nestStart nest ++ starts }
-- Selector context need to be inserted deeper in the nest.
insertContext nest@NestLoop{} context@ContextSelect{}
| nestContainsRate nest (contextOuterRate context)
, Just inner' <- insertContext (nestInner nest) context
, Just starts <- startsForContext context
= Just $ nest
{ nestInner = inner'
, nestStart = nestStart nest ++ starts }
-- Selector context inserted inside an existing selector context.
insertContext nest@NestGuard{} context@ContextSelect{}
| nestInnerRate nest == contextOuterRate context
= Just $ nest { nestInner = nestInner nest <> nestOfContext context }
-- Drop Segment Context -------------------------
-- Selector context goes at this level in the loop nest.
insertContext nest@NestLoop{} context@ContextSegment{}
| nestRate nest == contextOuterRate context
, Just starts <- startsForContext context
= Just $ nest
{ nestInner = nestInner nest <> nestOfContext context
, nestStart = nestStart nest ++ starts }
insertContext _nest _context
= Nothing
-------------------------------------------------------------------------------
-- | Insert starting statements in the given context.
insertStarts :: Nest -> TypeF -> [StmtStart] -> Maybe Nest
insertStarts nest tRate starts'
= case nest of
NestLoop{}
-- Desired context is right here.
| tRate == nestRate nest
-> Just $ nest { nestStart = nestStart nest ++ starts' }
-- Desired context is deeper in the nest.
-- The starting statements run before all interations of it.
| nestContainsRate nest tRate
-> Just $ nest { nestStart = nestStart nest ++ starts' }
_ -> Nothing
-------------------------------------------------------------------------------
-- | Insert starting statements in the given context.
insertBody :: Nest -> TypeF -> [StmtBody] -> Maybe Nest
insertBody nest tRate body'
= case nest of
NestLoop{}
-- Desired context is right here.
| tRate == nestRate nest
-> Just $ nest { nestBody = nestBody nest ++ body' }
-- Desired context is deeper in the nest.
| Just inner' <- insertBody (nestInner nest) tRate body'
-> Just $ nest { nestInner = inner' }
NestGuard{}
-- Desired context is right here.
| tRate == nestInnerRate nest
-> Just $ nest { nestBody = nestBody nest ++ body' }
-- Desired context is deeper in the nest.
| Just inner' <- insertBody (nestInner nest) tRate body'
-> Just $ nest { nestInner = inner' }
NestSegment{}
-- Desired context is right here.
| tRate == nestInnerRate nest
-> Just $ nest { nestBody = nestBody nest ++ body' }
-- Desired context is deeper in the nest.
| Just inner' <- insertBody (nestInner nest) tRate body'
-> Just $ nest { nestInner = inner' }
NestList (n : ns)
| Just n' <- insertBody n tRate body'
-> Just $ NestList (n':ns)
| Just (NestList ns') <- insertBody (NestList ns) tRate body'
-> Just $ NestList (n:ns')
_ -> Nothing
-------------------------------------------------------------------------------
-- | Insert ending statements in the given context.
insertEnds :: Nest -> TypeF -> [StmtEnd] -> Maybe Nest
insertEnds nest tRate ends'
= case nest of
NestLoop{}
-- Desired context is right here.
| tRate == nestRate nest
-> Just $ nest { nestEnd = nestEnd nest ++ ends' }
-- Desired context is deeper in the nest.
-- The ending statements run before all iterations of it.
| nestContainsRate nest tRate
-> Just $ nest { nestEnd = nestEnd nest ++ ends' }
_ -> Nothing
-- Rate Predicates ------------------------------------------------------------
-- | Check whether the top-level of this nest contains the given rate.
-- It might be in a nested context.
nestContainsRate :: Nest -> TypeF -> Bool
nestContainsRate nest tRate
= case nest of
NestEmpty
-> False
NestList ns
-> any (flip nestContainsRate tRate) ns
NestLoop{}
-> nestRate nest == tRate
|| nestContainsRate (nestInner nest) tRate
NestGuard{}
-> nestInnerRate nest == tRate
|| nestContainsRate (nestInner nest) tRate
NestSegment{}
-> nestInnerRate nest == tRate
|| nestContainsRate (nestInner nest) tRate
-- | Check whether the given rate is the inner rate of some
-- `NestGuard` constructor.
nestContainsGuardedRate :: Nest -> TypeF -> Bool
nestContainsGuardedRate nest tRate
= case nest of
NestEmpty
-> False
NestList ns
-> any (flip nestContainsRate tRate) ns
NestLoop{}
-> nestContainsGuardedRate (nestInner nest) tRate
NestGuard{}
-> nestInnerRate nest == tRate
|| nestContainsGuardedRate (nestInner nest) tRate
NestSegment{}
-> nestContainsGuardedRate (nestInner nest) tRate
-- Skeleton nests -------------------------------------------------------------
-- | Yield a skeleton nest for a given context.
nestOfContext :: Context -> Nest
nestOfContext context
= case context of
ContextRate tRate
-> NestLoop
{ nestRate = tRate
, nestStart = []
, nestBody = []
, nestInner = NestEmpty
, nestEnd = []
, nestResult = xUnit }
ContextSelect{}
-> NestGuard
{ nestOuterRate = contextOuterRate context
, nestInnerRate = contextInnerRate context
, nestFlags = contextFlags context
, nestBody = []
, nestInner = NestEmpty }
ContextSegment{}
-> NestSegment
{ nestOuterRate = contextOuterRate context
, nestInnerRate = contextInnerRate context
, nestLength = contextLens context
, nestBody = []
, nestInner = NestEmpty }
-- | For selector and segment contexts, make statements that initialize a
-- counter for how many times the context has been entered.
startsForContext :: Context -> Maybe [StmtStart]
startsForContext context
= case context of
ContextSelect{}
-> let TVar (UName nK) = contextInnerRate context
nCounter = NameVarMod nK "count"
in Just [ StartAcc
{ startAccName = nCounter
, startAccType = tNat
, startAccExp = xNat 0 }]
ContextSegment{}
-> let TVar (UName nK) = contextInnerRate context
nCounter = NameVarMod nK "count"
in Just [ StartAcc
{ startAccName = nCounter
, startAccType = tNat
, startAccExp = xNat 0 }]
_ -> Nothing