packages feed

fir-0.1.0.0: src/CodeGen/Array.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments      #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE PatternSynonyms     #-}
{-# LANGUAGE PolyKinds           #-}
{-# LANGUAGE RebindableSyntax    #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeOperators       #-}

{-|
Module: CodeGen.Array

This module defines the AST for a loop creating an array, to be processed by the code generator to define loops over arrays.

This is done here with the user-facing syntax of the library, instead of wiring in the definition.
-}

module CodeGen.Array
  ( createArray )
  where

-- base
import Data.Type.Equality
  ( (:~:)(Refl) )
import GHC.TypeLits
  ( KnownSymbol )
import GHC.TypeNats
  ( KnownNat )
import Unsafe.Coerce
  ( unsafeCoerce )

-- fir
import Control.Monad.Indexed
  ( pure, (>>), (>>=) )
import Control.Type.Optic
  ( Name, AnIndex, (:.:) )
import Data.Type.Known
  ( knownValue )
import Data.Type.Map
  ( (:->)((:->)) )
import Math.Algebra.Class
  ( AdditiveMonoid(fromInteger, (+)) )
import Math.Logic.Class
  ( Ord((<)) )
import FIR.AST
  ( AST, Code
  , Syntactic(toAST)
  , pattern Lit
  )
import FIR.AST.Type
  ( Eff )
import FIR.Binding
  ( Var, RW )
import FIR.Prelude
import FIR.Prim.Array
  ( Array )
import FIR.Prim.Types
  ( PrimTy, HasOpaqueType )
import FIR.ProgramState
  ( ProgramState(ProgramState) )
import FIR.Syntax.AST
  ( )
import FIR.Syntax.Program
  ( def, get, put, assign
  , locally, while
  )
import FIR.Validation.Bindings
  ( Has, CanGet, CanPut
  , ValidDef, AddBinding
  )

----------------------------------------------------------------------------

-- | Code for a loop creating a new array.
--
-- Assumes that the array has already been defined,
-- but allows it to be uninitialised.
--
-- Runs in an environment with no local state.
createArray :: forall n arrName ixName a i j ctx cfg funs eps g_iface rayQs bkend.
             ( KnownNat n
             , KnownSymbol ixName
             , KnownSymbol arrName
             , PrimTy a
             , i ~ 'ProgramState '[ arrName ':-> Var RW (Array n a) ] ctx cfg funs eps g_iface rayQs bkend
             , j ~ AddBinding ixName (Var RW Word32) i
             , Has ixName  j ~ Word32
             , Has arrName j ~ Array n a
             , CanGet ixName  j
             , CanPut ixName  j
             , CanGet arrName j
             , CanPut arrName j
             , ValidDef ixName i Word32
             )
          => ( Code Word32 -> Code a )
          -> AST ( Eff i i (Array n a) )
createArray arrayFunction
  | Refl <- ( unsafeCoerce Refl :: HasOpaqueType a :~: False ) -- bypass validity check
  = toAST $ locally @i @j do
      _ <- def @ixName @RW @Word32 @i 0
      while ( get @ixName < pure (Lit arrayLg) ) do
        i <- get @ixName
        assign @(Name arrName :.: AnIndex Word32)
          i (arrayFunction i)
        put @ixName (i+1)
      get @arrName
        where arrayLg :: Word32
              arrayLg = knownValue @n