Commit 25f8d040 authored by dterei's avatar dterei
Browse files

Fix floating point constants in LLVM backend (#7600).

parent 5cca0b44
...@@ -18,6 +18,8 @@ import Unique ...@@ -18,6 +18,8 @@ import Unique
-- from NCG -- from NCG
import PprBase import PprBase
import GHC.Float
-- ----------------------------------------------------------------------------- -- -----------------------------------------------------------------------------
-- * LLVM Basic Types and Variables -- * LLVM Basic Types and Variables
-- --
...@@ -227,7 +229,8 @@ getLit :: LlvmLit -> String ...@@ -227,7 +229,8 @@ getLit :: LlvmLit -> String
getLit (LMIntLit i (LMInt 32)) = show (fromInteger i :: Int32) getLit (LMIntLit i (LMInt 32)) = show (fromInteger i :: Int32)
getLit (LMIntLit i (LMInt 64)) = show (fromInteger i :: Int64) getLit (LMIntLit i (LMInt 64)) = show (fromInteger i :: Int64)
getLit (LMIntLit i _ ) = show (fromInteger i :: Int) getLit (LMIntLit i _ ) = show (fromInteger i :: Int)
getLit (LMFloatLit r LMFloat ) = fToStr $ realToFrac r -- See Note [LLVM Float Types].
getLit (LMFloatLit r LMFloat ) = (dToStr . widenFp . narrowFp) r
getLit (LMFloatLit r LMDouble) = dToStr r getLit (LMFloatLit r LMDouble) = dToStr r
getLit f@(LMFloatLit _ _) = error $ "Can't print this float literal!" ++ show f getLit f@(LMFloatLit _ _) = error $ "Can't print this float literal!" ++ show f
getLit (LMNullLit _ ) = "null" getLit (LMNullLit _ ) = "null"
...@@ -792,6 +795,8 @@ instance Show LlvmCastOp where ...@@ -792,6 +795,8 @@ instance Show LlvmCastOp where
-- | Convert a Haskell Double to an LLVM hex encoded floating point form. In -- | Convert a Haskell Double to an LLVM hex encoded floating point form. In
-- Llvm float literals can be printed in a big-endian hexadecimal format, -- Llvm float literals can be printed in a big-endian hexadecimal format,
-- regardless of underlying architecture. -- regardless of underlying architecture.
--
-- See Note [LLVM Float Types].
dToStr :: Double -> String dToStr :: Double -> String
dToStr d dToStr d
= let bs = doubleToBytes d = let bs = doubleToBytes d
...@@ -804,13 +809,30 @@ dToStr d ...@@ -804,13 +809,30 @@ dToStr d
str = map toUpper $ concat . fixEndian . (map hex) $ bs str = map toUpper $ concat . fixEndian . (map hex) $ bs
in "0x" ++ str in "0x" ++ str
-- | Convert a Haskell Float to an LLVM hex encoded floating point form. -- Note [LLVM Float Types]
-- LLVM uses the same encoding for both floats and doubles (16 digit hex -- ~~~~~~~~~~~~~~~~~~~~~~~
-- string) but floats must have the last half all zeroes so it can fit into -- We use 'dToStr' for both printing Float and Double floating point types. This is
-- a float size type. -- as LLVM expects all floating point constants (single & double) to be in IEEE
{-# NOINLINE fToStr #-} -- 754 Double precision format. However, for single precision numbers (Float)
fToStr :: Float -> String -- they should be *representable* in IEEE 754 Single precision format. So the
fToStr = (dToStr . realToFrac) -- easiest way to do this is to narrow and widen again.
-- (i.e., Double -> Float -> Double). We must be careful doing this that GHC
-- doesn't optimize that away.
-- Note [narrowFp & widenFp]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
-- NOTE: we use float2Double & co directly as GHC likes to optimize away
-- successive calls of 'realToFrac', defeating the narrowing. (Bug #7600).
-- 'realToFrac' has inconsistent behaviour with optimisation as well that can
-- also cause issues, these methods don't.
narrowFp :: Double -> Float
{-# NOINLINE narrowFp #-}
narrowFp = double2Float
widenFp :: Float -> Double
{-# NOINLINE widenFp #-}
widenFp = float2Double
-- | Reverse or leave byte data alone to fix endianness on this target. -- | Reverse or leave byte data alone to fix endianness on this target.
fixEndian :: [a] -> [a] fixEndian :: [a] -> [a]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment