{-# LANGUAGE CPP #-}
-- !!! Bug # 7600.
-- The LLVM backend can be tricky to get right with floating point constants
-- and GHC. See Note [LLVM Float Types] in compiler/llvmGen/Llvm/Types.hs for
-- why this is.
--
-- Two issues to watch for (that this bug tries to track):
--
-- 1) We need to narrow a double to a float but then expand back out (so that
-- we end up with the precision of a float but in double precision byte form).
-- GHC seems to optimize this away for some ways of doing this.
--
-- 2) The 'realToFrac' method returns different results at the byte level
-- depending on if optimisations are on or off. We use the double2float and
-- float2Double methods instead as they don't suffer from this.
-- 
-- Also worth looking at ticket # 3676 about issues with 'realToFrac'.
module Main (main) where

-- Required for WORDS_BIGENDIAN
#include <ghcautoconf.h>

import T7600_A

-- a fp constant that requires double precision, but we only use a single
-- precision type.
-- expected output: float 0x7FF0000000000000
float_number :: Float
float_number = 1.82173691287639817263897126389712638972163e+300

-- as above but use double precision so we can represent it.
-- expected output: double 0x7E45C3163C1ACF96
double_number :: Double
double_number = 1.82173691287639817263897126389712638972163e+300

-- Test run
main :: IO ()
main = test_run float_number double_number



-- XXX: We don't run below, but it can be useful to test how the optimizer is
-- running... the NOINLINE pragmas are needed below generally, but often not
-- for Bug31_A as the constant is in a different module...

-- -- Test run
-- test_run' :: Float -> Double -> IO ()
-- test_run' float_number double_number = do
--     print $ dToStr double_number
--     print $ dToStr (widen $ narrow double_number)
--     print $ dToStr (widen' $ narrow' double_number)
--     let dd = case double_number of { (D# x) -> x }
--     print $ dToStr (D# (float2Double# (double2Float# dd)))
--
-- -- use standard Haskell functions for type conversion... which are kind of
-- -- insane (see ticket # 3676) [these fail when -O0 is used...]
-- {-# NOINLINE narrow #-}
-- narrow :: Double -> Float
-- narrow = realToFrac
-- 
-- {-# NOINLINE widen #-}
-- widen :: Float -> Double
-- widen = realToFrac
-- 
-- -- use GHC specific functions which work as expected [work for both -O0 and -O]
-- {-# NOINLINE narrow' #-}
-- narrow' :: Double -> Float
-- narrow' = double2Float
-- 
-- {-# NOINLINE widen' #-}
-- widen' :: Float -> Double
-- widen' = float2Double
-- 
-- doubleToBytes :: Double -> [Int]
-- doubleToBytes d
--    = runST (do
--         arr <- newArray_ ((0::Int),7)
--         writeArray arr 0 d
--         arr <- castDoubleToWord8Array arr
--         i0 <- readArray arr 0
--         i1 <- readArray arr 1
--         i2 <- readArray arr 2
--         i3 <- readArray arr 3
--         i4 <- readArray arr 4
--         i5 <- readArray arr 5
--         i6 <- readArray arr 6
--         i7 <- readArray arr 7
--         return (map fromIntegral [i0,i1,i2,i3,i4,i5,i6,i7])
--      )
-- 
-- castFloatToWord8Array :: STUArray s Int Float -> ST s (STUArray s Int Word8)
-- castFloatToWord8Array = castSTUArray
-- 
-- castDoubleToWord8Array :: STUArray s Int Double -> ST s (STUArray s Int Word8)
-- castDoubleToWord8Array = castSTUArray
-- 
-- dToStr :: Double -> String
-- dToStr d
--   = let bs     = doubleToBytes d
--         hex d' = case showHex d' "" of
--                      []    -> error "dToStr: too few hex digits for float"
--                      [x]   -> ['0',x]
--                      [x,y] -> [x,y]
--                      _     -> error "dToStr: too many hex digits for float"
-- 
--         str  = map toUpper $ concat . fixEndian . (map hex) $ bs
--     in  "0x" ++ str
-- 
-- fixEndian :: [a] -> [a]
-- -- #if defined(WORDS_BIGENDIAN)
-- -- fixEndian = id
-- -- #else
-- fixEndian = reverse
-- -- #endif

