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

Reply via email to