{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module What4.InterpretedFloatingPoint
(
type FloatInfo
, HalfFloat
, SingleFloat
, DoubleFloat
, QuadFloat
, X86_80Float
, DoubleDoubleFloat
, FloatInfoRepr(..)
, X86_80Val(..)
, fp80ToBits
, fp80ToRational
, FloatInfoToPrecision
, FloatPrecisionToInfo
, floatInfoToPrecisionRepr
, floatPrecisionToInfoRepr
, FloatInfoToBitWidth
, floatInfoToBVTypeRepr
, SymInterpretedFloatType
, SymInterpretedFloat
, IsInterpretedFloatExprBuilder(..)
, IsInterpretedFloatSymExprBuilder(..)
) where
import Data.Bits
import Data.Hashable
import Data.Kind
import Data.Parameterized.Classes
import Data.Parameterized.TH.GADT
import Data.Ratio
import Data.Word ( Word16, Word64 )
import GHC.TypeNats
import Text.PrettyPrint.ANSI.Leijen
import What4.BaseTypes
import What4.Interface
data FloatInfo where
HalfFloat :: FloatInfo
SingleFloat :: FloatInfo
DoubleFloat :: FloatInfo
QuadFloat :: FloatInfo
X86_80Float :: FloatInfo
DoubleDoubleFloat :: FloatInfo
type HalfFloat = 'HalfFloat
type SingleFloat = 'SingleFloat
type DoubleFloat = 'DoubleFloat
type QuadFloat = 'QuadFloat
type X86_80Float = 'X86_80Float
type DoubleDoubleFloat = 'DoubleDoubleFloat
data FloatInfoRepr (fi :: FloatInfo) where
HalfFloatRepr :: FloatInfoRepr HalfFloat
SingleFloatRepr :: FloatInfoRepr SingleFloat
DoubleFloatRepr :: FloatInfoRepr DoubleFloat
QuadFloatRepr :: FloatInfoRepr QuadFloat
X86_80FloatRepr :: FloatInfoRepr X86_80Float
DoubleDoubleFloatRepr :: FloatInfoRepr DoubleDoubleFloat
instance KnownRepr FloatInfoRepr HalfFloat where knownRepr = HalfFloatRepr
instance KnownRepr FloatInfoRepr SingleFloat where knownRepr = SingleFloatRepr
instance KnownRepr FloatInfoRepr DoubleFloat where knownRepr = DoubleFloatRepr
instance KnownRepr FloatInfoRepr QuadFloat where knownRepr = QuadFloatRepr
instance KnownRepr FloatInfoRepr X86_80Float where knownRepr = X86_80FloatRepr
instance KnownRepr FloatInfoRepr DoubleDoubleFloat where knownRepr = DoubleDoubleFloatRepr
$(return [])
instance HashableF FloatInfoRepr where
hashWithSaltF = hashWithSalt
instance Hashable (FloatInfoRepr fi) where
hashWithSalt = $(structuralHashWithSalt [t|FloatInfoRepr|] [])
instance Pretty (FloatInfoRepr fi) where
pretty = text . show
instance Show (FloatInfoRepr fi) where
showsPrec = $(structuralShowsPrec [t|FloatInfoRepr|])
instance ShowF FloatInfoRepr
instance TestEquality FloatInfoRepr where
testEquality = $(structuralTypeEquality [t|FloatInfoRepr|] [])
instance OrdF FloatInfoRepr where
compareF = $(structuralTypeOrd [t|FloatInfoRepr|] [])
type family FloatInfoToPrecision (fi :: FloatInfo) :: FloatPrecision where
FloatInfoToPrecision HalfFloat = Prec16
FloatInfoToPrecision SingleFloat = Prec32
FloatInfoToPrecision DoubleFloat = Prec64
FloatInfoToPrecision X86_80Float = Prec80
FloatInfoToPrecision QuadFloat = Prec128
type family FloatPrecisionToInfo (fpp :: FloatPrecision) :: FloatInfo where
FloatPrecisionToInfo Prec16 = HalfFloat
FloatPrecisionToInfo Prec32 = SingleFloat
FloatPrecisionToInfo Prec64 = DoubleFloat
FloatPrecisionToInfo Prec80 = X86_80Float
FloatPrecisionToInfo Prec128 = QuadFloat
type family FloatInfoToBitWidth (fi :: FloatInfo) :: GHC.TypeNats.Nat where
FloatInfoToBitWidth HalfFloat = 16
FloatInfoToBitWidth SingleFloat = 32
FloatInfoToBitWidth DoubleFloat = 64
FloatInfoToBitWidth X86_80Float = 80
FloatInfoToBitWidth QuadFloat = 128
FloatInfoToBitWidth DoubleDoubleFloat = 128
floatInfoToPrecisionRepr
:: FloatInfoRepr fi -> FloatPrecisionRepr (FloatInfoToPrecision fi)
floatInfoToPrecisionRepr = \case
HalfFloatRepr -> knownRepr
SingleFloatRepr -> knownRepr
DoubleFloatRepr -> knownRepr
QuadFloatRepr -> knownRepr
X86_80FloatRepr -> knownRepr
DoubleDoubleFloatRepr -> error "double-double is not an IEEE-754 format."
floatPrecisionToInfoRepr
:: FloatPrecisionRepr fpp -> FloatInfoRepr (FloatPrecisionToInfo fpp)
floatPrecisionToInfoRepr fpp
| Just Refl <- testEquality fpp (knownRepr :: FloatPrecisionRepr Prec16)
= knownRepr
| Just Refl <- testEquality fpp (knownRepr :: FloatPrecisionRepr Prec32)
= knownRepr
| Just Refl <- testEquality fpp (knownRepr :: FloatPrecisionRepr Prec64)
= knownRepr
| Just Refl <- testEquality fpp (knownRepr :: FloatPrecisionRepr Prec80)
= knownRepr
| Just Refl <- testEquality fpp (knownRepr :: FloatPrecisionRepr Prec128)
= knownRepr
| otherwise
= error $ "unexpected IEEE-754 precision: " ++ show fpp
floatInfoToBVTypeRepr
:: FloatInfoRepr fi -> BaseTypeRepr (BaseBVType (FloatInfoToBitWidth fi))
floatInfoToBVTypeRepr = \case
HalfFloatRepr -> knownRepr
SingleFloatRepr -> knownRepr
DoubleFloatRepr -> knownRepr
QuadFloatRepr -> knownRepr
X86_80FloatRepr -> knownRepr
DoubleDoubleFloatRepr -> knownRepr
data X86_80Val = X86_80Val
Word16
Word64
deriving (Show, Eq, Ord)
fp80ToBits :: X86_80Val -> Integer
fp80ToBits (X86_80Val ex mantissa) =
shiftL (toInteger ex) 64 .|. toInteger mantissa
fp80ToRational :: X86_80Val -> Maybe Rational
fp80ToRational (X86_80Val ex mantissa)
| ex' == 0x7FFF = Nothing
| otherwise = Just $! (if s then negate else id) (m * (1 % 2^e))
where
s = testBit ex 15
ex' = ex .&. 0x7FFF
m = (toInteger mantissa) % ((2::Integer)^(63::Integer))
e = 16382 - toInteger ex'
type family SymInterpretedFloatType (sym :: Type) (fi :: FloatInfo) :: BaseType
type SymInterpretedFloat sym fi = SymExpr sym (SymInterpretedFloatType sym fi)
class IsExprBuilder sym => IsInterpretedFloatExprBuilder sym where
iFloatPZero :: sym -> FloatInfoRepr fi -> IO (SymInterpretedFloat sym fi)
iFloatNZero :: sym -> FloatInfoRepr fi -> IO (SymInterpretedFloat sym fi)
iFloatNaN :: sym -> FloatInfoRepr fi -> IO (SymInterpretedFloat sym fi)
iFloatPInf :: sym -> FloatInfoRepr fi -> IO (SymInterpretedFloat sym fi)
iFloatNInf :: sym -> FloatInfoRepr fi -> IO (SymInterpretedFloat sym fi)
iFloatLit
:: sym -> FloatInfoRepr fi -> Rational -> IO (SymInterpretedFloat sym fi)
iFloatLitSingle :: sym -> Float -> IO (SymInterpretedFloat sym SingleFloat)
iFloatLitDouble :: sym -> Double -> IO (SymInterpretedFloat sym DoubleFloat)
iFloatLitLongDouble :: sym -> X86_80Val -> IO (SymInterpretedFloat sym X86_80Float)
iFloatNeg
:: sym
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatAbs
:: sym
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatSqrt
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatAdd
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatSub
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatMul
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatDiv
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatRem
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatMin
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatMax
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatFMA
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatEq
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatNe
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatFpEq
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatFpNe
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatLe
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatLt
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatGe
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatGt
:: sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (Pred sym)
iFloatIsNaN :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsInf :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsZero :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsPos :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsNeg :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsSubnorm :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIsNorm :: sym -> SymInterpretedFloat sym fi -> IO (Pred sym)
iFloatIte
:: sym
-> Pred sym
-> SymInterpretedFloat sym fi
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatCast
:: sym
-> FloatInfoRepr fi
-> RoundingMode
-> SymInterpretedFloat sym fi'
-> IO (SymInterpretedFloat sym fi)
iFloatRound
:: sym
-> RoundingMode
-> SymInterpretedFloat sym fi
-> IO (SymInterpretedFloat sym fi)
iFloatFromBinary
:: sym
-> FloatInfoRepr fi
-> SymBV sym (FloatInfoToBitWidth fi)
-> IO (SymInterpretedFloat sym fi)
iFloatToBinary
:: sym
-> FloatInfoRepr fi
-> SymInterpretedFloat sym fi
-> IO (SymBV sym (FloatInfoToBitWidth fi))
iBVToFloat
:: (1 <= w)
=> sym
-> FloatInfoRepr fi
-> RoundingMode
-> SymBV sym w
-> IO (SymInterpretedFloat sym fi)
iSBVToFloat
:: (1 <= w) => sym
-> FloatInfoRepr fi
-> RoundingMode
-> SymBV sym w
-> IO (SymInterpretedFloat sym fi)
iRealToFloat
:: sym
-> FloatInfoRepr fi
-> RoundingMode
-> SymReal sym
-> IO (SymInterpretedFloat sym fi)
iFloatToBV
:: (1 <= w)
=> sym
-> NatRepr w
-> RoundingMode
-> SymInterpretedFloat sym fi
-> IO (SymBV sym w)
iFloatToSBV
:: (1 <= w)
=> sym
-> NatRepr w
-> RoundingMode
-> SymInterpretedFloat sym fi
-> IO (SymBV sym w)
iFloatToReal :: sym -> SymInterpretedFloat sym fi -> IO (SymReal sym)
iFloatBaseTypeRepr
:: sym
-> FloatInfoRepr fi
-> BaseTypeRepr (SymInterpretedFloatType sym fi)
class (IsSymExprBuilder sym, IsInterpretedFloatExprBuilder sym) => IsInterpretedFloatSymExprBuilder sym where
freshFloatConstant
:: sym
-> SolverSymbol
-> FloatInfoRepr fi
-> IO (SymExpr sym (SymInterpretedFloatType sym fi))
freshFloatConstant sym nm fi = freshConstant sym nm $ iFloatBaseTypeRepr sym fi
freshFloatLatch
:: sym
-> SolverSymbol
-> FloatInfoRepr fi
-> IO (SymExpr sym (SymInterpretedFloatType sym fi))
freshFloatLatch sym nm fi = freshLatch sym nm $ iFloatBaseTypeRepr sym fi
freshFloatBoundVar
:: sym
-> SolverSymbol
-> FloatInfoRepr fi
-> IO (BoundVar sym (SymInterpretedFloatType sym fi))
freshFloatBoundVar sym nm fi = freshBoundVar sym nm $ iFloatBaseTypeRepr sym fi