content: {-# LANGUAGE BangPatterns  #-}
  {-# LANGUAGE CPP           #-}
  {-# LANGUAGE TypeOperators #-}
  -- |
  -- Module:      : Data.Array.Accelerate.Examples.Internal.Backend
  -- Copyright    : [2014..2020] Trevor L. McDonell
  -- License      : BSD3
  --
  -- Maintainer   : Trevor L. McDonell <trevor.mcdonell@gmail.com>
  -- Stability    : experimental
  -- Portability  : non-portable (GHC extensions)
  --
  -- This file is all that should need editing in order to add support for new
  -- backends to the accelerate-examples package.
  --
  
  module Data.Array.Accelerate.Examples.Internal.Backend
    where
  
  import Prelude                                                      as P
  import Data.Label
  import System.Console.GetOpt
  
  import Data.Array.Accelerate
  import Data.Array.Accelerate.Trafo                                  ( Afunction )
  import Data.Array.Accelerate.Trafo.Sharing                          ( AfunctionR )
  import qualified Data.Array.Accelerate.Interpreter                  as Interp
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
  import qualified Data.Array.Accelerate.LLVM.Native                  as CPU
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
  import qualified Data.Array.Accelerate.LLVM.PTX                     as PTX
  #endif
  
  
  -- | Execute Accelerate expressions
  --
  run :: Arrays a => Backend -> Acc a -> a
  run Interpreter = Interp.run
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
  run CPU         = CPU.run
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
  run PTX         = PTX.run
  #endif
  
  run1 :: (Arrays a, Arrays b) => Backend -> (Acc a -> Acc b) -> a -> b
  run1 = runN
  
  runN :: Afunction f => Backend -> f -> AfunctionR f
  runN Interpreter = Interp.runN
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
  runN CPU         = CPU.runN
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
  runN PTX         = PTX.runN
  #endif
  
  
  -- | The set of backends available to execute the program.
  --
  data Backend = Interpreter
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
               | CPU
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
               | PTX
  #endif
    deriving (P.Eq, P.Enum, P.Bounded)
  
  
  -- The choice of show instance is important because this will be used to
  -- generate the command line flag.
  --
  instance Show Backend where
    show Interpreter      = "interpreter"
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
    show CPU              = "llvm-cpu"
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
    show PTX              = "llvm-ptx"
  #endif
  
  
  -- The default backend to use. Use one of the accelerated backends whenever
  -- available.
  --
  defaultBackend :: Backend
  defaultBackend =
    case maxBound of
      Interpreter -> Interpreter
      _           -> succ Interpreter
  
  
  -- The set of available backnds. This will be used for both the command line
  -- options as well as the fancy header generation.
  --
  availableBackends :: (options :-> Backend) -> [OptDescr (options -> options)]
  availableBackends optBackend =
    [ Option  [] [show Interpreter]
              (NoArg (set optBackend Interpreter))
              "reference implementation (sequential, slow)"
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
    , Option  [] [show CPU]
              (NoArg (set optBackend CPU))
              "LLVM based implementation for multicore CPUs (parallel)"
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
    , Option  [] [show PTX]
              (NoArg (set optBackend PTX))
              "LLVM based implementation for NVIDIA GPUs (parallel)"
  #endif
    ]
  
  
  -- By default, how many instances of the backend can be run concurrently?
  --
  -- If this returns `Nothing` then we make no changes to the configuration and
  -- inherit the RTS options. If this is `Just n`, then by default only `n`
  -- threads will be used to run tests at once. This option can still be
  -- overridden via the command line flags, it just sets a default.
  --
  -- e.g.
  --   * A multicore CPU backend may specify `Just 1`, so that only one instance
  --     runs at once, and it inherits all threads specified via `+RTS -Nn`
  --
  --   * A thread-safe accelerator backend can specify `Nothing`, while a
  --     non-thread-safe backend (perhaps it requires exclusive access to the
  --     accelerator board) should specify `Just 1`.
  --
  -- Both the LLVM-CPU and LLVM-PTX backends are safe to run concurrently given
  -- the same execution context. Although this results in over-subscription,
  -- particularly for the CPU backend, it still improves performance because the
  -- majority of the time is spent in the reference implementation / checking
  -- results, so running multiple tests concurrently is still useful.
  --
  concurrentBackends :: Backend -> Maybe Int
  concurrentBackends Interpreter  = Nothing
  #ifdef ACCELERATE_LLVM_NATIVE_BACKEND
  concurrentBackends CPU          = Nothing
  #endif
  #ifdef ACCELERATE_LLVM_PTX_BACKEND
  concurrentBackends PTX          = Nothing
  #endif
  
  