-- | Possibly convenient facilities for constructing constants.
module Futhark.IR.Prop.Constants
  ( IsValue (..),
    constant,
    intConst,
    floatConst,
  )
where

import Futhark.IR.Syntax.Core (SubExp (..))
import Language.Futhark.Primitive

-- | If a Haskell type is an instance of 'IsValue', it means that a
-- value of that type can be converted to a Futhark 'PrimValue'.
-- This is intended to cut down on boilerplate when writing compiler
-- code - for example, you'll quickly grow tired of writing @Constant
-- (LogVal True) loc@.
class IsValue a where
  value :: a -> PrimValue

instance IsValue Int8 where
  value :: Int8 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue) -> (Int8 -> IntValue) -> Int8 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> IntValue
Int8Value

instance IsValue Int16 where
  value :: Int16 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Int16 -> IntValue) -> Int16 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> IntValue
Int16Value

instance IsValue Int32 where
  value :: Int32 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Int32 -> IntValue) -> Int32 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> IntValue
Int32Value

instance IsValue Int64 where
  value :: Int64 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Int64 -> IntValue) -> Int64 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> IntValue
Int64Value

instance IsValue Word8 where
  value :: Word8 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Word8 -> IntValue) -> Word8 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> IntValue
Int8Value (Int8 -> IntValue) -> (Word8 -> Int8) -> Word8 -> IntValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int8
forall a b. (Integral a, Num b) => a -> b
fromIntegral

instance IsValue Word16 where
  value :: Word16 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Word16 -> IntValue) -> Word16 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> IntValue
Int16Value (Int16 -> IntValue) -> (Word16 -> Int16) -> Word16 -> IntValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral

instance IsValue Word32 where
  value :: Word32 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Word32 -> IntValue) -> Word32 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> IntValue
Int32Value (Int32 -> IntValue) -> (Word32 -> Int32) -> Word32 -> IntValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral

instance IsValue Word64 where
  value :: Word64 -> PrimValue
value = IntValue -> PrimValue
IntValue (IntValue -> PrimValue)
-> (Word64 -> IntValue) -> Word64 -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> IntValue
Int64Value (Int64 -> IntValue) -> (Word64 -> Int64) -> Word64 -> IntValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral

instance IsValue Double where
  value :: Double -> PrimValue
value = FloatValue -> PrimValue
FloatValue (FloatValue -> PrimValue)
-> (Double -> FloatValue) -> Double -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> FloatValue
Float64Value

instance IsValue Float where
  value :: Float -> PrimValue
value = FloatValue -> PrimValue
FloatValue (FloatValue -> PrimValue)
-> (Float -> FloatValue) -> Float -> PrimValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Float -> FloatValue
Float32Value

instance IsValue Bool where
  value :: Bool -> PrimValue
value = Bool -> PrimValue
BoolValue

instance IsValue PrimValue where
  value :: PrimValue -> PrimValue
value = PrimValue -> PrimValue
forall a. a -> a
id

instance IsValue IntValue where
  value :: IntValue -> PrimValue
value = IntValue -> PrimValue
IntValue

instance IsValue FloatValue where
  value :: FloatValue -> PrimValue
value = FloatValue -> PrimValue
FloatValue

-- | Create a 'Constant' 'SubExp' containing the given value.
constant :: (IsValue v) => v -> SubExp
constant :: forall v. IsValue v => v -> SubExp
constant = PrimValue -> SubExp
Constant (PrimValue -> SubExp) -> (v -> PrimValue) -> v -> SubExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. v -> PrimValue
forall a. IsValue a => a -> PrimValue
value

-- | Utility definition for reasons of type ambiguity.
intConst :: IntType -> Integer -> SubExp
intConst :: IntType -> Integer -> SubExp
intConst IntType
t Integer
v = IntValue -> SubExp
forall v. IsValue v => v -> SubExp
constant (IntValue -> SubExp) -> IntValue -> SubExp
forall a b. (a -> b) -> a -> b
$ IntType -> Integer -> IntValue
forall int. Integral int => IntType -> int -> IntValue
intValue IntType
t Integer
v

-- | Utility definition for reasons of type ambiguity.
floatConst :: FloatType -> Double -> SubExp
floatConst :: FloatType -> Double -> SubExp
floatConst FloatType
t Double
v = FloatValue -> SubExp
forall v. IsValue v => v -> SubExp
constant (FloatValue -> SubExp) -> FloatValue -> SubExp
forall a b. (a -> b) -> a -> b
$ FloatType -> Double -> FloatValue
forall num. Real num => FloatType -> num -> FloatValue
floatValue FloatType
t Double
v