OK old thread but some progress!
I narrowed down what I was talking about to a small test case. Follows bellow:
=====================
module Main where
import Data.Array.ST
import Control.Monad.ST
import Data.Word
import Data.Char
import Numeric
import System.IO
-- Test runner
main = do
putStr "Enter a double: "
hFlush stdout
d <- double
print $ "Float Version (inline) : " ++ (getLit True $ floatD d)
print $ "Float Version (noinline): " ++ (getLit False $ floatD d)
print $ "Double Version : " ++ (getLit True $ doubleD d)
double :: IO Double
double = do
x <- getLine
return $ read x
floatD d = LMFloatLit d LMFloat
doubleD d = LMFloatLit d LMDouble
-- -----------------------------------------------------------------------------
-- Data types
--
data LlvmType = LMFloat | LMDouble
data LlvmLit = LMFloatLit Double LlvmType
getLit :: Bool -> LlvmLit -> String
getLit True (LMFloatLit r LMFloat ) = fToStr $ realToFrac r
getLit False (LMFloatLit r LMFloat ) = fToStrNI $ realToFrac r
getLit _ (LMFloatLit r LMDouble) = dToStr r
-- -----------------------------------------------------------------------------
-- * Floating point conversion
--
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 . reverse . (map hex) $ bs
in "0x" ++ str
fToStr :: Float -> String
fToStr = (dToStr . realToFrac)
{-# NOINLINE fToStrNI #-}
fToStrNI :: Float -> String
fToStrNI = (dToStr . realToFrac)
-- -----------------------------------------------------------------------------
-- Converting floating-point literals to integrals for printing
castDoubleToWord8Array :: STUArray s Int Double -> ST s (STUArray s Int Word8)
castDoubleToWord8Array = castSTUArray
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])
)
=====================
If you compile this with -O and -fasm and on x86 the 'bug' occurs
(both with 6.12.3 and HEAD):
$ ghc -fasm -O --make T.hs
$ ./T
Enter a double: 2.0e-2
"Float Version (inline) : 0x3F947AE147AE147B"
"Float Version (noinline): 0x3F947AE140000000"
"Double Version : 0x3F947AE147AE147B"
If you compile the program with -fllvm or -fvia-C then the inline and
noinline version of Float give the same (and correct) output. I
haven't investigated the native code generator yet to find out why its
doing this, will look into that soonish unless someone knows the
answer already.
On 24 September 2010 19:46, Simon Peyton-Jones <[email protected]> wrote:
> | fits into a float. I was doing this before basically be having
> | something like ((realToFrac :: Double -> Float) . (realToFrac :: Float
> | -> Double)). Recently GHC seems to have learned to optimise this by
> | removing that code completely. (Before if I told GHC not to inline
> | some stuff this stopped it doing that, but not anymore it seems).
>
> I'm agnostic about whether optimising realToFrac . realToFrac to the identity
> is OK (though I'd have thought so), but I don't think I see how it happens!
> Maybe a RULE? But I don't see one. If you can show it happening that'd be
> interesting.
>
> Simon
>
_______________________________________________
Cvs-ghc mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/cvs-ghc