id,summary,reporter,owner,description,type,status,priority,milestone,component,version,resolution,keywords,cc,os,architecture,failure,difficulty,testcase,blockedby,blocking,related
2269,Word type to Double or Float conversions are slower than Int conversions,dons,dons@galois.com,"We have int2Double# and int2Float# primitives, but not equivalent ones for Word
types. We may need word2Double# too, for Words* to be fully first-class performance-wise.

This means we have to do extra tests in the Num instances for Word types
to implement 'fromIntegral':

{{{

    toInteger (W# x#)
        | i# >=# 0#             = smallInteger i#
        | otherwise             = wordToInteger x#
        where i# = word2Int# x#

}}}

Now, for some types, we work around this:

{{{

""fromIntegral/Int->Word""  fromIntegral = \(I# x#) -> W# (int2Word# x#)
""fromIntegral/Word->Int""  fromIntegral = \(W# x#) -> I# (word2Int# x#)
""fromIntegral/Word->Word"" fromIntegral = id :: Word -> Word

}}}

and so on for other Word/Int types. And all is fine.

The problem comes up for Float and Double. For Int, we can write:

{{{

""fromIntegral/Int->Float""   fromIntegral = int2Float
""fromIntegral/Int->Double""  fromIntegral = int2Double

int2Float :: Int -> Float
int2Float   (I# x) = F# (int2Float# x)

int2Double :: Int -> Double 
int2Double   (I# x) = D# (int2Double#   x)

}}}

But we can't write these rules for Word types.

The result is a slow down on Word conversions, consider this
program:

{{{

main = print . sumU
             . mapU (fromIntegral::Int->Double)
             $ enumFromToU 0 100000000

}}}

When in lhs is Int, we get this nice code:

{{{

$wfold :: Double# -> Int# -> Double#

$wfold =
  \ (ww_s18k :: Double#) (ww1_s18o :: Int#) ->
    case ># ww1_s18o 100000000 of wild_a14T {
      False ->
        $wfold
          (+## ww_s18k (int2Double# ww1_s18o)) (+# ww1_s18o 1);
      True -> ww_s18k


}}}

But for Word types, we get:

{{{

$wfold :: Double# -> Word# -> Double#

$wfold =
  \ (ww_s1gN :: Double#) (ww1_s1gR :: Word#) ->
    case gtWord# ww1_s1gR __word 100000000 of wild_a1do {
      False ->
        case case >=# (word2Int# ww1_s1gR) 0 of wild1_a1cS {
               False ->
                 case word2Integer# ww1_s1gR of wild11_a1d9 { (# s_a1db, d_a1dc #) ->
                 case {__ccall __encodeDouble Int#
                        -> ByteArray#
                        -> Int#
                        -> State# RealWorld
                        -> (# State# RealWorld, Double# #)}_a1bT
                        s_a1db d_a1dc 0 realWorld#
                 of wild12_a1bX { (# ds1_a1bZ, ds2_a1c0 #) ->
                 ds2_a1c0
                 }
                 };
               True -> int2Double# (word2Int# ww1_s1gR)
             }
        of wild1_a1bM { __DEFAULT ->
        $wfold
          (+## ww_s1gN wild1_a1bM) (plusWord# ww1_s1gR __word 1)
        };
      True -> ww_s1gN
    }

}}}

Which is to be expected, and the running time goes from:

{{{

$ time ./henning  
5.00000000067109e17
./henning  1.53s user 0.00s system 99% cpu 1.534 total

}}}

To:

{{{

$ time ./henning  
5.00000000067109e17
./henning  4.57s user 0.00s system 99% cpu 4.571 total

}}}

So not too bad, but still, principle of least surprise says Word and Int
should behave the same.

Should we have a word2Double# primop?",feature request,new,lowest,7.6.2,Compiler,6.8.2,,"rules, performance, double",daniel.is.fischer@… dterei,Unknown/Multiple,Unknown/Multiple,Runtime performance bug,Unknown,,,,
