-- -- Copyright (c) 2009-2010, ERICSSON AB All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- -- * Redistributions of source code must retain the above copyright notice, -- this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- * Neither the name of the ERICSSON AB nor the names of its contributors -- may be used to endorse or promote products derived from this software -- without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS -- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -- THE POSSIBILITY OF SUCH DAMAGE. -- {-# LANGUAGE UndecidableInstances #-} -- | Primitive and helper functions supported by Feldspar module Feldspar.Core.Functions where import qualified Prelude import Feldspar.Range import Feldspar.Core.Types import Feldspar.Core.Expr import Feldspar.Core.Reify import Feldspar.Prelude import qualified Data.Bits as B infix 4 == infix 4 /= infix 4 < infix 4 > infix 4 <= infix 4 >= infixr 3 && infixr 3 &&* infixr 2 || infixr 2 ||* infix 1 ? -- * Misc. noSizeProp :: a -> () noSizeProp _ = () noSizeProp2 :: a -> b -> () noSizeProp2 _ _ = () class (Prelude.Eq a, Storable a) => Eq a where (==) :: Data a -> Data a -> Data Bool a == b | a Prelude.== b = true | otherwise = function2 "(==)" noSizeProp2 (Prelude.==) a b (/=) :: Data a -> Data a -> Data Bool a /= b | a Prelude.== b = false | otherwise = function2 "(/=)" noSizeProp2 (Prelude./=) a b optEq :: (Storable a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optEq a b | a Prelude.== b = true | sa `disjoint` sb = false | otherwise = function2 "(==)" noSizeProp2 (Prelude.==) a b where sa = dataSize a sb = dataSize b optNeq :: (Storable a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optNeq a b | a Prelude.== b = false | sa `disjoint` sb = true | otherwise = function2 "(/=)" noSizeProp2 (Prelude./=) a b where sa = dataSize a sb = dataSize b instance Eq Int where a == b = optEq a b a /= b = optNeq a b instance Eq Signed32 where a == b = optEq a b a /= b = optNeq a b instance Eq Unsigned32 where a == b = optEq a b a /= b = optNeq a b instance Eq Signed16 where a == b = optEq a b a /= b = optNeq a b instance Eq Unsigned16 where a == b = optEq a b a /= b = optNeq a b instance Eq Signed8 where a == b = optEq a b a /= b = optNeq a b instance Eq Unsigned8 where a == b = optEq a b a /= b = optNeq a b instance Eq Float where a == b = optEq a b a /= b = optNeq a b instance Eq Bool instance Eq () class (Prelude.Ord a, Eq a, Storable a) => Ord a where (<) :: Data a -> Data a -> Data Bool a < b | a Prelude.== b = false | otherwise = function2 "(<)" noSizeProp2 (Prelude.<) a b (>) :: Data a -> Data a -> Data Bool a > b | a Prelude.== b = false | otherwise = function2 "(>)" noSizeProp2 (Prelude.>) a b (<=) :: Data a -> Data a -> Data Bool a <= b | a Prelude.== b = true | otherwise = function2 "(<=)" noSizeProp2 (Prelude.<=) a b (>=) :: Data a -> Data a -> Data Bool a >= b | a Prelude.== b = true | otherwise = function2 "(>=)" noSizeProp2 (Prelude.>=) a b min :: Data a -> Data a -> Data a min a b = a Data a -> Data a max a b = a>b ? (a,b) optLT :: (Storable a, Prelude.Ord a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optLT a b | a Prelude.== b = false | sa `rangeLess` sb = true | sb `rangeLessEq` sa = false | otherwise = function2 "(<)" noSizeProp2 (Prelude.<) a b where sa = dataSize a sb = dataSize b optGT :: (Storable a, Prelude.Ord a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optGT a b | a Prelude.== b = false | sb `rangeLess` sa = true | sa `rangeLessEq` sb = false | otherwise = function2 "(>)" noSizeProp2 (Prelude.>) a b where sa = dataSize a sb = dataSize b optLTE :: (Storable a, Prelude.Ord a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optLTE a b | a Prelude.== b = true | sa `rangeLessEq` sb = true | sb `rangeLess` sa = false | otherwise = function2 "(<=)" noSizeProp2 (Prelude.<=) a b where sa = dataSize a sb = dataSize b optGTE :: (Storable a, Prelude.Ord a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data Bool optGTE a b | a Prelude.== b = true | sb `rangeLessEq` sa = true | sa `rangeLess` sb = false | otherwise = function2 "(>=)" noSizeProp2 (Prelude.>=) a b where sa = dataSize a sb = dataSize b optMin :: (Ord a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data a optMin a b = cap (rangeMin ra rb) $ case dataToExpr cond1 of Value _ -> cond1 ? (a,b) _ -> cond2 ? (b,a) where cond1 = a Data a -> Data a -> Data a optMax a b = cap (rangeMax ra rb) $ case dataToExpr cond1 of Value _ -> cond1 ? (a,b) _ -> cond2 ? (b,a) where cond1 = a>b cond2 = b>a ra = dataSize a rb = dataSize b instance Ord Int where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Unsigned32 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Signed32 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Unsigned16 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Signed16 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Unsigned8 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Signed8 where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b instance Ord Float where a < b = optLT a b a > b = optGT a b a <= b = optLTE a b a >= b = optGTE a b min a b = optMin a b max a b = optMax a b not :: Data Bool -> Data Bool not = function "not" noSizeProp Prelude.not -- | Selects the elements of the pair depending on the condition (?) :: Computable a => Data Bool -> (a,a) -> a cond ? (a,b) = ifThenElse cond (const a) (const b) unit (&&) :: Data Bool -> Data Bool -> Data Bool x && y = case (dataToExpr x, dataToExpr y) of (Value True, _) -> y (Value False,_) -> false (_, Value True) -> x (_,Value False) -> false _ -> function2 "(&&)" noSizeProp2 (Prelude.&&) x y (||) :: Data Bool -> Data Bool -> Data Bool x || y = case (dataToExpr x, dataToExpr y) of (Value True, _) -> true (Value False,_) -> y (_, Value True) -> true (_,Value False) -> y _ -> function2 "(||)" noSizeProp2 (Prelude.||) x y -- | Lazy conjunction, second argument only run if necessary (&&*) :: Computable a => (a -> Data Bool) -> (a -> Data Bool) -> (a -> Data Bool) (f &&* g) a = ifThenElse (f a) g (const false) a -- | Lazy disjunction, second argument only run if necessary (||*) :: Computable a => (a -> Data Bool) -> (a -> Data Bool) -> (a -> Data Bool) (f ||* g) a = ifThenElse (f a) (const true) g a class (Numeric a, Prelude.Integral a, Ord a, Storable a) => Integral a where quot :: Data a -> Data a -> Data a quot = function2 "quot" (\_ _ -> universal) Prelude.quot rem :: Data a -> Data a -> Data a rem = function2 "rem" (\_ _ -> universal) Prelude.rem div :: Data a -> Data a -> Data a div x y = rem x y /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ? (quotxy - 1, quotxy) where quotxy = quot x y mod :: Data a -> Data a -> Data a mod x y = remxy /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ? (remxy + y, remxy) where remxy = rem x y (^) :: Data a -> Data a -> Data a (^) = function2 "(^)" (\_ _ -> universal) (Prelude.^) optRem :: (Integral a, Size a ~ Range b, Prelude.Ord b, Num b, Enum b) => Data a -> Data a -> Data a optRem x y | abs rx `rangeLess` abs ry = x | otherwise = function2 "rem" rangeRem Prelude.rem x y where rx = dataSize x ry = dataSize y optMod :: (Integral a, Size a ~ Range b, Prelude.Ord b, Num b, Enum b) => Data a -> Data a -> Data a optMod x y = cap (rangeMod rx ry) $ remxy /= 0 && (x > 0 && y < 0 || x < 0 && y > 0) ? (remxy + y, remxy) where remxy = rem x y rx = dataSize x ry = dataSize y optSignedExp :: (Integral a, Bits a, Storable a, Size a ~ Range b, Prelude.Ord b, Num b) => Data a -> Data a -> Data a optSignedExp m e = case dataToExpr m of -- From Bit Twiddling Hacks -- "Conditionally negate a value without branching" -- Here we negate the value 1 if isOdd is true i.e. when e is -- and odd number Value (-1) -> cap (range (-1) 1) $ let isOdd = e .&. 1 in (1 `xor` (negate isOdd)) + isOdd _ -> optExp m e optExp :: (Integral a, Storable a) => Data a -> Data a -> Data a optExp m e = case (dataToExpr m,dataToExpr e) of (Value 1,_) -> value 1 (_,Value 1) -> m (_,Value 0) -> value 1 _ -> function2 "(^)" (\_ _ -> universal) (Prelude.^) m e instance Integral Int where rem = optRem mod = optMod (^) = optSignedExp instance Integral Signed32 where rem = optRem mod = optMod (^) = optSignedExp instance Integral Unsigned32 where div = quot rem = optRem mod = rem (^) = optExp instance Integral Signed16 where rem = optRem mod = optMod (^) = optSignedExp instance Integral Unsigned16 where div = quot rem = optRem mod = rem (^) = optExp instance Integral Signed8 where rem = optRem mod = optMod (^) = optSignedExp instance Integral Unsigned8 where div = quot rem = optRem mod = rem (^) = optExp -- * Loops -- | For-loop -- -- @`for` start end init body@: -- -- * @start@\/@end@ are the start\/end indexes. -- -- * @init@ is the starting state. -- -- * @body@ computes the next state given the current loop index (ranging over -- @[start .. end]@) and the current state. for :: Computable a => Data Int -> Data Int -> a -> (Data Int -> a -> a) -> a for start end init body = snd $ whileSized szCont szBody cont body' (start,init) where sziCont = rangeByRange (dataSize start) (dataSize end + 1) szCont = (sziCont,universal) sziBody = rangeByRange (dataSize start) (dataSize end) szBody = (sziBody,universal) cont (i,s) = i <= end body' (i,s) = (i+1, body i s) -- | A sequential \"unfolding\" of an vector -- -- @`unfoldCore` l init step@: -- -- * @l@ is the length of the resulting vector. -- -- * @init@ is the initial state. -- -- * @step@ is a function computing a new element and the next state from the -- current index and current state. The index is the position of the new -- element in the output vector. unfoldCore :: (Computable state, Storable a) => Data Length -> state -> (Data Int -> state -> (Data a, state)) -> (Data [a], state) unfoldCore l init step = for 0 (l-1) (outp,init) $ \i (o,state) -> let (a,state') = step i state in (setIx o i a, state') where outp = array (mapMonotonic fromIntegral (dataSize l) :> universal) [] class (Num a, Storable a) => Numeric a where fromIntegerNum :: Integer -> Data a fromIntegerNum = value . fromInteger absNum :: Data a -> Data a signumNum :: Data a -> Data a addNum :: Data a -> Data a -> Data a subNum :: Data a -> Data a -> Data a mulNum :: Data a -> Data a -> Data a absNum' :: (Numeric a, Num (Size a)) => Data a -> Data a absNum' = function "abs" abs abs optAbs :: (Numeric a, Size a ~ Range b, Num b, Prelude.Ord b) => Data a -> Data a optAbs x | isNatural rx = x | otherwise = absNum' x where rx = dataSize x signumNum' :: (Numeric a, Num (Size a)) => Data a -> Data a signumNum' = function "signum" signum signum optSignum :: (Numeric a, Size a ~ Range b, Num b, Prelude.Ord b) => Data a -> Data a optSignum x | 0 `rangeLess` rx = 1 | rx `rangeLess` 0 = -1 | rx Prelude.== 0 = 0 | otherwise = signumNum' x where rx = dataSize x optAdd :: (Numeric a, Num (Size a)) => Data a -> Data a -> Data a optAdd x y = case (dataToExpr x, dataToExpr y) of (Value 0, _) -> y (_, Value 0) -> x _ -> function2 "(+)" (+) (+) x y optSub :: (Numeric a, Num (Size a)) => Data a -> Data a -> Data a optSub x y = case dataToExpr y of Value 0 -> x _ -> function2 "(-)" (-) (-) x y optMul :: (Numeric a, Num (Size a)) => Data a -> Data a -> Data a optMul x y = case (dataToExpr x, dataToExpr y) of (Value 0,_) -> value 0 (_,Value 0) -> value 0 (Value 1,_) -> y (_,Value 1) -> x _ -> function2 "(*)" (*) (*) x y instance Numeric Int where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Unsigned32 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Signed32 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Unsigned16 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Signed16 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Unsigned8 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Signed8 where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric Float where absNum = optAbs signumNum = optSignum addNum = optAdd subNum = optSub mulNum = optMul instance Numeric a => Num (Data a) where fromInteger = fromIntegerNum abs = absNum signum = signumNum (+) = addNum (-) = subNum (*) = mulNum class (Fractional a, Storable a) => Fractional' a where fromRationalFrac :: Rational -> Data a fromRationalFrac = value . fromRational divFrac :: Data a -> Data a -> Data a instance Fractional' Float where divFrac = function2 "(/)" (\_ _ -> fullRange) (/) -- XXX Improve range instance (Fractional' a, Numeric a) => Fractional (Data a) where fromRational = fromRationalFrac (/) = divFrac -- * Bit manipulation infixl 5 <<,>> infixl 4 ⊕ -- | The following class provides functions for bit level manipulation class (B.Bits a, Storable a) => Bits a where -- Logical operations (.&.) :: Data a -> Data a -> Data a (.&.) = optAnd (.|.) :: Data a -> Data a -> Data a (.|.) = optOr xor :: Data a -> Data a -> Data a xor = optXor (⊕) :: Data a -> Data a -> Data a (⊕) = xor complement :: Data a -> Data a complement = function "complement" (const universal) B.complement -- Operations on individual bits bit :: Data Int -> Data a bit = function "bit" (const universal) B.bit setBit :: Data a -> Data Int -> Data a setBit = function2 "setBit" (\_ _ -> universal) B.setBit clearBit :: Data a -> Data Int -> Data a clearBit = function2 "clearBit" (\_ _ -> universal) B.clearBit complementBit :: Data a -> Data Int -> Data a complementBit = function2 "complementBit" (\_ _ -> universal) B.complementBit testBit :: Data a -> Data Int -> Data Bool testBit = function2 "testBit" noSizeProp2 B.testBit -- Moving bits around shiftL :: Data a -> Data Int -> Data a shiftL = optZero (function2 "shiftL" (\_ _ -> universal) B.shiftL) (<<) :: Data a -> Data Int -> Data a (<<) = shiftL shiftR :: Data a -> Data Int -> Data a shiftR = optZero (function2 "shiftR" (\_ _ -> universal) B.shiftR) (>>) :: Data a -> Data Int -> Data a (>>) = shiftR rotateL :: Data a -> Data Int -> Data a rotateL = optZero (function2 "rotateL" (\_ _ -> universal) B.rotateL) rotateR :: Data a -> Data Int -> Data a rotateR = optZero (function2 "rotateR" (\_ _ -> universal) B.rotateR) reverseBits :: Data a -> Data a reverseBits = function "reverseBits" (\_ -> universal) revBits -- Bulk bit operations -- | Returns the number of leading zeroes for unsigned types. -- For signed types it returns the number of unnecessary sign bits bitScan :: Data a -> Data Int bitScan = function "bitScan" (\_ -> universal) scanLeft bitCount :: Data a -> Data Int bitCount = function "bitCount" (\_ -> universal) countBits -- Queries about the type bitSize :: Data a -> Data Int bitSize = function "bitSize" (const naturalRange) B.bitSize isSigned :: Data a -> Data Bool isSigned = function "isSigned" noSizeProp B.isSigned optAnd :: (B.Bits a, Storable a) => Data a -> Data a -> Data a optAnd x y = case (dataToExpr x, dataToExpr y) of (Value 0, _) -> value 0 (_, Value 0) -> value 0 (Value x, _) | allOnes x -> y (_, Value y) | allOnes y -> x _ -> function2 "(.&.)" (\_ _ -> universal) (B..&.) x y optOr :: (B.Bits a, Storable a) => Data a -> Data a -> Data a optOr x y = case (dataToExpr x, dataToExpr y) of (Value 0, _) -> y (_, Value 0) -> x (Value x, _) | allOnes x -> value (B.complement 0) (_, Value y) | allOnes y -> value (B.complement 0) _ -> function2 "(.|.)" (\_ _ -> universal) (B..|.) x y optXor :: (Bits a, B.Bits a, Storable a) => Data a -> Data a -> Data a optXor x y = case (dataToExpr x, dataToExpr y) of (Value 0, _) -> y (_, Value 0) -> x (Value x, _) | allOnes x -> complement y (_, Value y) | allOnes y -> complement x _ -> function2 "xor" (\_ _ -> universal) B.xor x y allOnes :: (Prelude.Eq a, B.Bits a) => a -> Bool allOnes x = x Prelude.== B.complement 0 optZero :: (a -> Data Int -> a) -> a -> Data Int -> a optZero f x y = case dataToExpr y of Value 0 -> x _ -> f x y scanLeft :: B.Bits b => b -> Int scanLeft b = if B.isSigned b then scanLoop b (B.testBit b (B.bitSize b - 1)) (B.bitSize b - 2) 0 else scanLoop b False (B.bitSize b - 1) 0 where scanLoop b bit i n | i Prelude.< 0 = n scanLoop b bit i n | B.testBit b i Prelude./= bit = n scanLoop b bit i n | otherwise = scanLoop b bit (i-1) (n+1) countBits :: B.Bits b => b -> Int countBits b = loop b (B.bitSize b - 1) 0 where loop b i n | i Prelude.< 0 = n loop b i n | B.testBit b i = loop b (i-1) (n+1) loop b i n | otherwise = loop b (i-1) n revBits :: B.Bits b => b -> b revBits b = revLoop b 0 (0 `asTypeOf` b) where bitSize = B.bitSize b revLoop b i n | i Prelude.>= bitSize = n revLoop b i n | B.testBit b i = revLoop b (i+1) (B.setBit n (bitSize - i - 1)) revLoop b i n | otherwise = revLoop b (i+1) n instance Bits Int instance Bits Unsigned32 instance Bits Signed32 instance Bits Unsigned16 instance Bits Signed16 instance Bits Unsigned8 instance Bits Signed8