{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Synthesizer.LLVM.Filter.NonRecursive (
   convolve,
   convolvePacked,
   ) where

import qualified Synthesizer.LLVM.Causal.Process as Causal
import qualified Synthesizer.LLVM.Causal.Private as CausalPriv
import qualified Synthesizer.LLVM.Generator.Source as Source
import qualified Synthesizer.LLVM.Generator.Signal as Sig
import qualified Synthesizer.LLVM.RingBuffer as RingBuffer
import qualified Synthesizer.LLVM.Frame.SerialVector.Code as Serial

import qualified Synthesizer.Causal.Class as CausalClass
import Synthesizer.Causal.Class (($<))

import qualified LLVM.DSL.Expression as Expr
import LLVM.DSL.Expression (Exp)

import qualified LLVM.Extra.Multi.Value.Storable as Storable
import qualified LLVM.Extra.Multi.Value.Marshal as Marshal
import qualified LLVM.Extra.Multi.Value as MultiValue
import qualified LLVM.Extra.Multi.Vector as MultiVector
import qualified LLVM.Extra.Control as C
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.Tuple as Tuple

import qualified LLVM.Core as LLVM

import qualified Type.Data.Num.Decimal as TypeNum

import Foreign.Ptr (Ptr)
import Data.Word (Word)

import Control.Arrow ((<<<), (&&&))
import Control.Monad (liftM2)

import NumericPrelude.Numeric
import NumericPrelude.Base
import Prelude ()


{-
This is a brute-force implementation.
No Karatsuba, No Toom-Cook, No Fourier.
-}
convolve ::
   (Storable.C a, Marshal.C a, MultiValue.PseudoRing a, MultiValue.T a ~ am) =>
   Exp (Source.StorableVector a) -> Causal.T am am
convolve :: forall a am.
(C a, C a, PseudoRing a, T a ~ am) =>
Exp (StorableVector a) -> T am am
convolve Exp (StorableVector a)
mask =
   let len :: Exp Word
len = Exp (StorableVector a) -> Exp Word
forall a. Exp (StorableVector a) -> Exp Word
Source.storableVectorLength Exp (StorableVector a)
mask
   in ((forall r. T Word -> (T am, Value (Ptr a)) -> CodeGenFunction r am)
-> T (T Word, (T am, Value (Ptr a))) am
forall a b c.
(forall r. a -> b -> CodeGenFunction r c) -> T (a, b) c
CausalPriv.zipWith (\(MultiValue.Cons Repr Word
l) -> Value Word -> (T am, Value (Ptr a)) -> CodeGenFunction r am
forall a am r.
(C a, C a, T a ~ am, PseudoRing a) =>
Value Word -> (T am, Value (Ptr a)) -> CodeGenFunction r am
scalarProduct Repr Word
Value Word
l)
         T (T Word, (T am, Value (Ptr a))) am
-> SignalOf T (T Word) -> T (T am, Value (Ptr a)) am
forall (process :: * -> * -> *) a b c.
C process =>
process (a, b) c -> SignalOf process a -> process b c
$< Exp Word -> T (T Word)
forall ae al. (Aggregate ae al, C al) => ae -> T al
Sig.constant Exp Word
len)
      T (T am, Value (Ptr a)) am -> T am (T am, Value (Ptr a)) -> T am am
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
<<<
      Exp a -> Exp Word -> T am (T am)
forall ae al.
(Aggregate ae al, C al) =>
ae -> Exp Word -> T al (T al)
Causal.track Exp a
forall a. C a => Exp a
Expr.zero Exp Word
len T am (T am) -> T am (Value (Ptr a)) -> T am (T am, Value (Ptr a))
forall b c c'. T b c -> T b c' -> T b (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Exp (StorableVector a) -> T am (Value (Ptr a))
forall a x. C a => Exp (StorableVector a) -> T x (Value (Ptr a))
provideMask Exp (StorableVector a)
mask

convolvePacked ::
   (Marshal.Vector n a, MultiVector.PseudoRing a) =>
   (Storable.C a, MultiValue.PseudoRing a, Serial.Value n a ~ v) =>
   Exp (Source.StorableVector a) -> Causal.T v v
convolvePacked :: forall n a v.
(Vector n a, PseudoRing a, C a, PseudoRing a, Value n a ~ v) =>
Exp (StorableVector a) -> T v v
convolvePacked = Singleton n -> Exp (StorableVector a) -> T v v
forall n a v.
(Vector n a, PseudoRing a, C a, PseudoRing a, Value n a ~ v) =>
Singleton n -> Exp (StorableVector a) -> T v v
convolvePackedAux Singleton n
forall x. Integer x => Singleton x
TypeNum.singleton

convolvePackedAux ::
   (Marshal.Vector n a, MultiVector.PseudoRing a) =>
   (Storable.C a, MultiValue.PseudoRing a, Serial.Value n a ~ v) =>
   TypeNum.Singleton n -> Exp (Source.StorableVector a) -> Causal.T v v
convolvePackedAux :: forall n a v.
(Vector n a, PseudoRing a, C a, PseudoRing a, Value n a ~ v) =>
Singleton n -> Exp (StorableVector a) -> T v v
convolvePackedAux Singleton n
vectorSize Exp (StorableVector a)
mask =
   let len :: Exp Word
len = Exp (StorableVector a) -> Exp Word
forall a. Exp (StorableVector a) -> Exp Word
Source.storableVectorLength Exp (StorableVector a)
mask
   in ((forall r. T Word -> (T v, Value (Ptr a)) -> CodeGenFunction r v)
-> T (T Word, (T v, Value (Ptr a))) v
forall a b c.
(forall r. a -> b -> CodeGenFunction r c) -> T (a, b) c
CausalPriv.zipWith (\(MultiValue.Cons Repr Word
l) -> Value Word
-> (T (Value n a), Value (Ptr a)) -> CodeGenFunction r (Value n a)
forall a n r.
(C a, Vector n a, PseudoRing a) =>
Value Word
-> (T (Value n a), Value (Ptr a)) -> CodeGenFunction r (Value n a)
scalarProductPacked Repr Word
Value Word
l)
         T (T Word, (T v, Value (Ptr a))) v
-> SignalOf T (T Word) -> T (T v, Value (Ptr a)) v
forall (process :: * -> * -> *) a b c.
C process =>
process (a, b) c -> SignalOf process a -> process b c
$< Exp Word -> T (T Word)
forall ae al. (Aggregate ae al, C al) => ae -> T al
Sig.constant Exp Word
len)
      T (T v, Value (Ptr a)) v -> T v (T v, Value (Ptr a)) -> T v v
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
<<<
      Exp (T n a) -> Exp Word -> T v (T v)
forall ae al.
(Aggregate ae al, C al) =>
ae -> Exp Word -> T al (T al)
Causal.track Exp (T n a)
forall a. C a => Exp a
Expr.zero
         (Exp Word -> Exp Word -> Exp Word
divUp (Singleton n -> Exp Word
forall n a. (Integer n, Num a) => Singleton n -> a
TypeNum.integralFromSingleton Singleton n
vectorSize) Exp Word
len)
      T v (T v) -> T v (Value (Ptr a)) -> T v (T v, Value (Ptr a))
forall b c c'. T b c -> T b c' -> T b (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&&
      Exp (StorableVector a) -> T v (Value (Ptr a))
forall a x. C a => Exp (StorableVector a) -> T x (Value (Ptr a))
provideMask Exp (StorableVector a)
mask

divUp :: Exp Word -> Exp Word -> Exp Word
divUp :: Exp Word -> Exp Word -> Exp Word
divUp Exp Word
k Exp Word
n = Exp Word -> Exp Word -> Exp Word
forall a. Integral a => Exp a -> Exp a -> Exp a
Expr.idiv (Exp Word
nExp Word -> Exp Word -> Exp Word
forall a. C a => a -> a -> a
+(Exp Word
kExp Word -> Exp Word -> Exp Word
forall a. C a => a -> a -> a
-Exp Word
1)) Exp Word
k

provideMask ::
   (Storable.C a) =>
   Exp (Source.StorableVector a) -> Causal.T x (LLVM.Value (Ptr a))
provideMask :: forall a x. C a => Exp (StorableVector a) -> T x (Value (Ptr a))
provideMask Exp (StorableVector a)
mask =
   SignalOf T (Value (Ptr a)) -> T x (Value (Ptr a))
forall b a. SignalOf T b -> T a b
forall (process :: * -> * -> *) b a.
C process =>
SignalOf process b -> process a b
CausalClass.fromSignal (SignalOf T (Value (Ptr a)) -> T x (Value (Ptr a)))
-> SignalOf T (Value (Ptr a)) -> T x (Value (Ptr a))
forall a b. (a -> b) -> a -> b
$
   (T (StorableVector a) -> Value (Ptr a))
-> SignalOf T (T (StorableVector a)) -> SignalOf T (Value (Ptr a))
forall a b. (a -> b) -> SignalOf T a -> SignalOf T b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(MultiValue.Cons (Value (Ptr a)
ptr,Value Word
_l)) -> Value (Ptr a)
ptr) (SignalOf T (T (StorableVector a)) -> SignalOf T (Value (Ptr a)))
-> SignalOf T (T (StorableVector a)) -> SignalOf T (Value (Ptr a))
forall a b. (a -> b) -> a -> b
$
   Exp (StorableVector a) -> T (T (StorableVector a))
forall ae al. (Aggregate ae al, C al) => ae -> T al
Sig.constant Exp (StorableVector a)
mask


scalarProduct ::
   (Storable.C a, Marshal.C a, MultiValue.T a ~ am, MultiValue.PseudoRing a) =>
   LLVM.Value Word ->
   (RingBuffer.T am, LLVM.Value (Ptr a)) ->
   LLVM.CodeGenFunction r am
scalarProduct :: forall a am r.
(C a, C a, T a ~ am, PseudoRing a) =>
Value Word -> (T am, Value (Ptr a)) -> CodeGenFunction r am
scalarProduct Value Word
n (T am
rb,Value (Ptr a)
mask) =
   ((Value Word, am) -> am)
-> CodeGenFunction r (Value Word, am) -> CodeGenFunction r am
forall a b. (a -> b) -> CodeGenFunction r a -> CodeGenFunction r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Value Word, am) -> am
forall a b. (a, b) -> b
snd (CodeGenFunction r (Value Word, am) -> CodeGenFunction r am)
-> CodeGenFunction r (Value Word, am) -> CodeGenFunction r am
forall a b. (a -> b) -> a -> b
$
   Value Word
-> Value (Ptr a)
-> (Value Word, am)
-> (Value (Ptr a)
    -> (Value Word, am) -> CodeGenFunction r (Value Word, am))
-> CodeGenFunction r (Value Word, am)
forall s i a ptrA r.
(Phi s, Num i, IsConst i, IsInteger i, CmpRet i, IsPrimitive i,
 Storable a, Value (Ptr a) ~ ptrA) =>
Value i
-> ptrA
-> s
-> (ptrA -> s -> CodeGenFunction r s)
-> CodeGenFunction r s
Storable.arrayLoop Value Word
n Value (Ptr a)
mask (Value Word
forall a. Additive a => a
A.zero, am
forall a. Additive a => a
A.zero) ((Value (Ptr a)
  -> (Value Word, am) -> CodeGenFunction r (Value Word, am))
 -> CodeGenFunction r (Value Word, am))
-> (Value (Ptr a)
    -> (Value Word, am) -> CodeGenFunction r (Value Word, am))
-> CodeGenFunction r (Value Word, am)
forall a b. (a -> b) -> a -> b
$ \Value (Ptr a)
ptr (Value Word
k, am
s) -> do
      am
a <- Value Word -> T am -> CodeGenFunction r am
forall a r. C a => Value Word -> T a -> CodeGenFunction r a
RingBuffer.index Value Word
k T am
rb
      T a
b <- Value (Ptr a) -> CodeGenFunction r (T a)
forall a r. C a => Value (Ptr a) -> CodeGenFunction r (T a)
forall r. Value (Ptr a) -> CodeGenFunction r (T a)
Storable.load Value (Ptr a)
ptr
      (Value Word -> am -> (Value Word, am))
-> CodeGenFunction r (Value Word)
-> CodeGenFunction r am
-> CodeGenFunction r (Value Word, am)
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (,) (Value Word -> CodeGenFunction r (Value Word)
forall a r.
(IsArithmetic a, IsConst a, Num a) =>
Value a -> CodeGenFunction r (Value a)
A.inc Value Word
k) (am -> am -> CodeGenFunction r am
forall r. am -> am -> CodeGenFunction r am
forall a r. Additive a => a -> a -> CodeGenFunction r a
A.add am
s (am -> CodeGenFunction r am)
-> CodeGenFunction r am -> CodeGenFunction r am
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< am -> am -> CodeGenFunction r am
forall r. am -> am -> CodeGenFunction r am
forall a r. PseudoRing a => a -> a -> CodeGenFunction r a
A.mul am
a am
T a
b)


scalarProductPacked ::
   (Storable.C a, Marshal.Vector n a, MultiVector.PseudoRing a) =>
   LLVM.Value Word ->
   (RingBuffer.T (Serial.Value n a), LLVM.Value (Ptr a)) ->
   LLVM.CodeGenFunction r (Serial.Value n a)
scalarProductPacked :: forall a n r.
(C a, Vector n a, PseudoRing a) =>
Value Word
-> (T (Value n a), Value (Ptr a)) -> CodeGenFunction r (Value n a)
scalarProductPacked Value Word
n0 (T (Value n a)
rb,Value (Ptr a)
mask0) = do
   (Value n a
ax, Iterator n a
rx) <- T (Value n a) -> CodeGenFunction r (Value n a, Iterator n a)
forall n a r.
(Positive n, Vector n a) =>
T (Value n a) -> CodeGenFunction r (Value n a, Iterator n a)
readSerialStart T (Value n a)
rb
   T a
bx <- Value (Ptr a) -> CodeGenFunction r (T a)
forall a r. C a => Value (Ptr a) -> CodeGenFunction r (T a)
forall r. Value (Ptr a) -> CodeGenFunction r (T a)
Storable.load Value (Ptr a)
mask0
   Value n a
sx <- T a -> Value n a -> CodeGenFunction r (Value n a)
forall n a r.
(Positive n, PseudoRing a) =>
T a -> Value n a -> CodeGenFunction r (Value n a)
Serial.scale T a
bx Value n a
ax
   Value Word
n1 <- Value Word -> CodeGenFunction r (Value Word)
forall a r.
(IsArithmetic a, IsConst a, Num a) =>
Value a -> CodeGenFunction r (Value a)
A.dec Value Word
n0
   Value (Ptr a)
mask1 <- Value (Ptr a) -> CodeGenFunction r (Value (Ptr a))
forall a ptr r.
(Storable a, Value (Ptr a) ~ ptr) =>
ptr -> CodeGenFunction r ptr
Storable.incrementPtr Value (Ptr a)
mask0
   ((Iterator n a, Value n a) -> Value n a)
-> CodeGenFunction r (Iterator n a, Value n a)
-> CodeGenFunction r (Value n a)
forall a b. (a -> b) -> CodeGenFunction r a -> CodeGenFunction r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Iterator n a, Value n a) -> Value n a
forall a b. (a, b) -> b
snd (CodeGenFunction r (Iterator n a, Value n a)
 -> CodeGenFunction r (Value n a))
-> CodeGenFunction r (Iterator n a, Value n a)
-> CodeGenFunction r (Value n a)
forall a b. (a -> b) -> a -> b
$ Value Word
-> Value (Ptr a)
-> (Iterator n a, Value n a)
-> (Value (Ptr a)
    -> (Iterator n a, Value n a)
    -> CodeGenFunction r (Iterator n a, Value n a))
-> CodeGenFunction r (Iterator n a, Value n a)
forall s i a ptrA r.
(Phi s, Num i, IsConst i, IsInteger i, CmpRet i, IsPrimitive i,
 Storable a, Value (Ptr a) ~ ptrA) =>
Value i
-> ptrA
-> s
-> (ptrA -> s -> CodeGenFunction r s)
-> CodeGenFunction r s
Storable.arrayLoop Value Word
n1 Value (Ptr a)
mask1 (Iterator n a
rx, Value n a
sx) ((Value (Ptr a)
  -> (Iterator n a, Value n a)
  -> CodeGenFunction r (Iterator n a, Value n a))
 -> CodeGenFunction r (Iterator n a, Value n a))
-> (Value (Ptr a)
    -> (Iterator n a, Value n a)
    -> CodeGenFunction r (Iterator n a, Value n a))
-> CodeGenFunction r (Iterator n a, Value n a)
forall a b. (a -> b) -> a -> b
$ \Value (Ptr a)
ptr (Iterator n a
r1, Value n a
s1) -> do
      (Value n a
a,Iterator n a
r2) <- T (Value n a)
-> Iterator n a -> CodeGenFunction r (Value n a, Iterator n a)
forall a n r.
(C a, Vector n a) =>
T (Value n a)
-> Iterator n a -> CodeGenFunction r (Value n a, Iterator n a)
readSerialNext T (Value n a)
rb Iterator n a
r1
      T a
b <- Value (Ptr a) -> CodeGenFunction r (T a)
forall a r. C a => Value (Ptr a) -> CodeGenFunction r (T a)
forall r. Value (Ptr a) -> CodeGenFunction r (T a)
Storable.load Value (Ptr a)
ptr
      (Value n a -> (Iterator n a, Value n a))
-> CodeGenFunction r (Value n a)
-> CodeGenFunction r (Iterator n a, Value n a)
forall a b. (a -> b) -> CodeGenFunction r a -> CodeGenFunction r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((,) Iterator n a
r2) (Value n a -> Value n a -> CodeGenFunction r (Value n a)
forall a r. Additive a => a -> a -> CodeGenFunction r a
forall r. Value n a -> Value n a -> CodeGenFunction r (Value n a)
A.add Value n a
s1 (Value n a -> CodeGenFunction r (Value n a))
-> CodeGenFunction r (Value n a) -> CodeGenFunction r (Value n a)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< T a -> Value n a -> CodeGenFunction r (Value n a)
forall n a r.
(Positive n, PseudoRing a) =>
T a -> Value n a -> CodeGenFunction r (Value n a)
Serial.scale T a
b Value n a
a)


type
   Iterator n a =
      ((Serial.Value n a,
        {-
        I would like to use Serial.Iterator,
        but we need to read in reversed order,
        that is, from high to low indices.
        -}
        Serial.Value n a,
        LLVM.Value Word),
       LLVM.Value Word)

readSerialStart ::
   (TypeNum.Positive n, Marshal.Vector n a) =>
   RingBuffer.T (Serial.Value n a) ->
   LLVM.CodeGenFunction r (Serial.Value n a, Iterator n a)
readSerialStart :: forall n a r.
(Positive n, Vector n a) =>
T (Value n a) -> CodeGenFunction r (Value n a, Iterator n a)
readSerialStart T (Value n a)
rb = do
   Value n a
a <- Value Word -> T (Value n a) -> CodeGenFunction r (Value n a)
forall a r. C a => Value Word -> T a -> CodeGenFunction r a
RingBuffer.index Value Word
forall a. Additive a => a
A.zero T (Value n a)
rb
   (Value n a, Iterator n a)
-> CodeGenFunction r (Value n a, Iterator n a)
forall a. a -> CodeGenFunction r a
forall (m :: * -> *) a. Monad m => a -> m a
return (Value n a
a, ((Value n a
a, Value n a
forall a. Undefined a => a
Tuple.undef, Value Word
forall a. Additive a => a
A.zero), Value Word
forall a. Additive a => a
A.zero))

readSerialNext ::
   (MultiValue.C a, Marshal.Vector n a) =>
   RingBuffer.T (Serial.Value n a) ->
   Iterator n a ->
   LLVM.CodeGenFunction r (Serial.Value n a, Iterator n a)
readSerialNext :: forall a n r.
(C a, Vector n a) =>
T (Value n a)
-> Iterator n a -> CodeGenFunction r (Value n a, Iterator n a)
readSerialNext T (Value n a)
rb ((Value n a
a0,Value n a
r0,Value Word
j0), Value Word
k0) = do
   Value Bool
vectorEnd <- CmpPredicate
-> Value Word
-> Value Word
-> CodeGenFunction r (CmpResult (Value Word))
forall r.
CmpPredicate
-> Value Word
-> Value Word
-> CodeGenFunction r (CmpResult (Value Word))
forall a r.
Comparison a =>
CmpPredicate -> a -> a -> CodeGenFunction r (CmpResult a)
A.cmp CmpPredicate
LLVM.CmpEQ Value Word
j0 Value Word
forall a. Additive a => a
A.zero
   ((Value n a
r1,Value Word
j1), Value Word
k1) <-
      Value Bool
-> ((Value n a, Value Word), Value Word)
-> CodeGenFunction r ((Value n a, Value Word), Value Word)
-> CodeGenFunction r ((Value n a, Value Word), Value Word)
forall a r.
Phi a =>
Value Bool -> a -> CodeGenFunction r a -> CodeGenFunction r a
C.ifThen Value Bool
vectorEnd ((Value n a
r0,Value Word
j0), Value Word
k0) (CodeGenFunction r ((Value n a, Value Word), Value Word)
 -> CodeGenFunction r ((Value n a, Value Word), Value Word))
-> CodeGenFunction r ((Value n a, Value Word), Value Word)
-> CodeGenFunction r ((Value n a, Value Word), Value Word)
forall a b. (a -> b) -> a -> b
$ do
         Value Word
k <- Value Word -> CodeGenFunction r (Value Word)
forall a r.
(IsArithmetic a, IsConst a, Num a) =>
Value a -> CodeGenFunction r (Value a)
A.inc Value Word
k0
         Value n a
r <- Value Word -> T (Value n a) -> CodeGenFunction r (Value n a)
forall a r. C a => Value Word -> T a -> CodeGenFunction r a
RingBuffer.index Value Word
k T (Value n a)
rb
         ((Value n a, Value Word), Value Word)
-> CodeGenFunction r ((Value n a, Value Word), Value Word)
forall a. a -> CodeGenFunction r a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Value n a
r, Word -> Value Word
forall a. IsConst a => a -> Value a
LLVM.valueOf (Value n a -> Word
forall n i a. (Positive n, Integral i) => Value n a -> i
Serial.size Value n a
r :: Word)), Value Word
k)
   Value Word
j2 <- Value Word -> CodeGenFunction r (Value Word)
forall a r.
(IsArithmetic a, IsConst a, Num a) =>
Value a -> CodeGenFunction r (Value a)
A.dec Value Word
j1
   (T a
ai,Value n a
r2) <- T a -> Value n a -> CodeGenFunction r (T a, Value n a)
forall n x a v r.
(Positive n, C x, T x ~ a, Value n x ~ v) =>
a -> v -> CodeGenFunction r (a, v)
Serial.shiftUp T a
forall a. Undefined a => a
Tuple.undef Value n a
r1
   (T a
_, Value n a
a1) <- T a -> Value n a -> CodeGenFunction r (T a, Value n a)
forall n x a v r.
(Positive n, C x, T x ~ a, Value n x ~ v) =>
a -> v -> CodeGenFunction r (a, v)
Serial.shiftUp T a
ai Value n a
a0
   (Value n a, ((Value n a, Value n a, Value Word), Value Word))
-> CodeGenFunction
     r (Value n a, ((Value n a, Value n a, Value Word), Value Word))
forall a. a -> CodeGenFunction r a
forall (m :: * -> *) a. Monad m => a -> m a
return (Value n a
a1, ((Value n a
a1,Value n a
r2,Value Word
j2), Value Word
k1))