packages feed

pure-borrow-0.1.0.0: src/Control/Concurrent/DivideConquer/Linear/Internal.hs

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -fno-spec-constr #-}
{-# OPTIONS_HADDOCK hide #-}

{- |
The FFT butterfly, kept in its own module solely so that
@-fno-spec-constr@ can apply to it and nothing else.

SpecConstr on this loop defeats the specialization that
@pure-borrow-inspection@ requires: at @-O2@ the @combine loop has no
type-class dictionaries@ assertion fails without the flag. Setting the flag
on "Control.Concurrent.DivideConquer.Linear" instead would also disable
SpecConstr for the scheduler, the Chase-Lev queue and the worker loop, which
measures up to 32% slower on @fft.worksteal@. The flag is module-scoped and
has no per-binding form, so a one-binding module is the only way to scope it
correctly.
-}
module Control.Concurrent.DivideConquer.Linear.Internal (
  combineLoop,
) where

import Control.Functor.Linear qualified as Control
import Control.Monad.Borrow.Pure.BO
import Data.Complex (Complex)
import Data.Vector.Generic qualified as G
import Data.Vector.Generic.Mutable.Linear.Borrow.Unrestricted qualified as Vector
import Prelude.Linear
import Prelude qualified as P

combineLoop ::
  (G.Vector v (Complex Double)) =>
  Int ->
  Complex Double ->
  Int ->
  Complex Double ->
  Mut α (Vector.Vector v (Complex Double)) %1 ->
  BO α ()
{-# INLINEABLE combineLoop #-}
combineLoop !half !root !index !weight vector
  | index >= half =
      Control.pure (consume vector)
  | otherwise = Control.do
      (Ur evenValue, vector) <-
        Vector.unsafeGet index vector
      (Ur oddValue, vector) <-
        Vector.unsafeGet (half + index) vector
      let !weightedOdd = weight P.* oddValue
      vector <-
        Vector.unsafeWrite
          index
          (evenValue P.+ weightedOdd)
          vector
      vector <-
        Vector.unsafeWrite
          (half + index)
          (evenValue P.- weightedOdd)
          vector
      combineLoop
        half
        root
        (index + 1)
        (weight P.* root)
        vector