packages feed

crackNum-3.30: src/CrackNum/Formats.hs

---------------------------------------------------------------------------
-- |
-- Module      :  CrackNum.Formats
-- Copyright   :  (c) Levent Erkok
-- License     :  BSD3
-- Maintainer  :  erkokl@gmail.com
-- Stability   :  experimental
--
-- The table of floating-point formats, and parsing the -f flag
-----------------------------------------------------------------------------

{-# LANGUAGE CPP #-}

{-# OPTIONS_GHC -Wall -Werror #-}

module CrackNum.Formats(
     fpFormats, fpFormatNames, fpFormatsHelp, getFP
   ) where

import Data.Char (isDigit)

import CrackNum.Types

#include "MachDeps.h"

#define FP_MIN_EB 1
#define FP_MIN_SB 1
#if WORD_SIZE_IN_BITS == 64
#define FP_MAX_EB 61
#define FP_MAX_SB 4611686018427387902
#else
#define FP_MAX_EB 29
#define FP_MAX_SB 1073741822
#endif

-- | The floating-point formats we support, in the order we present them: the name to
-- pass to -f, what it is, and its (exponent + significand) sizes. The arbitrary format
-- stands in for any a+b pair rather than naming a format of its own, which is what the
-- final field records: only the named ones can be listed as choices.
fpFormats :: [(String, String, String, Bool)]
fpFormats = [ ("hp",      "Half float",             "( 5 +  11)", True )
            , ("bp",      "Brain float",            "( 8 +   8)", True )
            , ("tf32",    "TensorFloat-32",         "( 8 +  11)", True )
            , ("sp",      "Single precision",       "( 8 +  24)", True )
            , ("dp",      "Double precision",       "(11 +  53)", True )
            , ("qp",      "Quad   precision",       "(15 + 113)", True )
            , ("a+b",     "Arbitrary IEEE-754",     "( a +   b)", False)
            , ("e5m2",    "FP8 format (IEEE-754)",  "( 5 +   3)", True )
            , ("e4m3",    "FP8 format (Alternate)", "( 4 +   4)", True )
            , ("fp4",     "FP4 format (E2M1)",      "( 2 +   2)", True )
            , ("fp4e0m3", "FP4 format (E0M3)",      "( 0 +   3)", True )
            , ("e8m0",    "FP8 format (MX scale)",  "( 8 +   0)", True )
            ]

-- | The formats that can actually be named, i.e., everything but the arbitrary a+b
-- placeholder. This is what --list-formats prints, one per line.
fpFormatNames :: [String]
fpFormatNames = [n | (n, _, _, True) <- fpFormats]

-- | Floating-point formats we support, as a table for use in help/error messages.
fpFormatsHelp :: [String]
fpFormatsHelp = [rjust n ++ ": " ++ ljust d ++ " " ++ sz | (n, d, sz, _) <- fpFormats]
  where nw      = maximum [length n | (n, _, _, _) <- fpFormats]
        dw      = maximum [length d | (_, d, _, _) <- fpFormats]
        rjust x = replicate (nw - length x) ' ' ++ x
        ljust x = x ++ replicate (dw - length x) ' '

-- | Given a float flag value, turn it into a flag
getFP :: String -> Flag
getFP "hp"      = Floating $ FP 5 11
getFP "bp"      = Floating $ FP 8  8
getFP "tf32"    = Floating $ FP 8 11
getFP "sp"      = Floating SP
getFP "dp"      = Floating DP
getFP "qp"      = Floating $ FP 15 113
getFP "e5m2"    = Floating E5M2
getFP "e4m3"    = Floating E4M3
getFP "fp4"     = Floating FP4
getFP "fp4e0m3" = Floating FP4E0M3
getFP "e8m0"    = Floating E8M0
getFP ab        = case span isDigit ab of
                  (eb@(_:_), '+':r) -> case span isDigit r of
                                        (sp@(_:_), "") -> mkEBSB (read eb) (read sp)
                                        _              -> bad
                  _                 -> bad
                where bad = BadFlag $ [ "Option " ++ show "-f" ++ " requires one of:"
                                      , ""
                                      ]
                                   ++ fpFormatsHelp
                                   ++ [ ""
                                      , "In the arbitrary format, the first number is the number of bits in the exponent"
                                      , "and the second number is the number of bits in the significand, including the implicit bit."
                                      ]
                      mkEBSB :: Int -> Int -> Flag
                      mkEBSB eb sb
                       |    eb >= FP_MIN_EB && eb <= FP_MAX_EB
                         && sb >= FP_MIN_SB && sb <= FP_MAX_SB
                       = Floating $ FP eb sb
                       | True
                       = BadFlag [ "Invalid floating-point precision."
                                 , ""
                                 , "  Exponent    size must be between " ++ show (FP_MIN_EB :: Int) ++ " to "  ++ show (FP_MAX_EB :: Int)
                                 , "  Significant size must be between " ++ show (FP_MIN_SB :: Int) ++ " to "  ++ show (FP_MAX_SB :: Int)
                                 , ""
                                 , "Received: " ++ show eb ++ " " ++ show sb
                                 ]