summaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
authorErik de Castro Lopo <erikd@mega-nerd.com>2017-04-12 14:09:49 -0400
committerBen Gamari <ben@smart-cactus.org>2017-04-12 14:53:06 -0400
commitaa206346e6f12c9f88fdf051185741761ea88fbb (patch)
tree3963e016c48662f00cf5c53cf3d75af05322092d /libraries
parentbb3712bf772fecb965f56a356ccf61437d324dcf (diff)
downloadhaskell-aa206346e6f12c9f88fdf051185741761ea88fbb.tar.gz
base: Implement bit casts between word and float types
Test Plan: Test on x86 and x86_64 Reviewers: duncan, trofi, simonmar, tibbe, hvr, austin, rwbarton, bgamari Reviewed By: duncan Subscribers: Phyx, DemiMarie, rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3358
Diffstat (limited to 'libraries')
-rw-r--r--libraries/base/GHC/Float.hs91
-rw-r--r--libraries/base/cbits/CastFloatWord.cmm69
2 files changed, 159 insertions, 1 deletions
diff --git a/libraries/base/GHC/Float.hs b/libraries/base/GHC/Float.hs
index 64467b338e..c534bafa07 100644
--- a/libraries/base/GHC/Float.hs
+++ b/libraries/base/GHC/Float.hs
@@ -1,8 +1,10 @@
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP
+ , GHCForeignImportPrim
, NoImplicitPrelude
, MagicHash
, UnboxedTuples
+ , UnliftedFFITypes
#-}
{-# LANGUAGE CApiFFI #-}
-- We believe we could deorphan this module, by moving lots of things
@@ -21,11 +23,13 @@
-- Stability : internal
-- Portability : non-portable (GHC Extensions)
--
--- The types 'Float' and 'Double', and the classes 'Floating' and 'RealFloat'.
+-- The types 'Float' and 'Double', the classes 'Floating' and 'RealFloat' and
+-- casting between Word32 and Float and Word64 and Double.
--
-----------------------------------------------------------------------------
#include "ieee-flpt.h"
+#include "MachDeps.h"
module GHC.Float
( module GHC.Float
@@ -46,6 +50,7 @@ import GHC.Enum
import GHC.Show
import GHC.Num
import GHC.Real
+import GHC.Word
import GHC.Arr
import GHC.Float.RealFracMethods
import GHC.Float.ConversionUtils
@@ -1253,3 +1258,87 @@ exponents returned by decodeFloat.
-}
clamp :: Int -> Int -> Int
clamp bd k = max (-bd) (min bd k)
+
+
+{-
+Note [Casting from integral to floating point types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To implement something like `reinterpret_cast` from C++ to go from a
+floating-point type to an integral type one might niavely think that the
+following should work:
+
+ cast :: Float -> Word32
+ cast (F# f#) = W32# (unsafeCoerce# f#)
+
+Unfortunately that is not the case, because all the `unsafeCoerce#` does is tell
+the compiler that the types have changed. When one does the above cast and
+tries to operate on the resulting `Word32` the code generator will generate code
+that performs an integer/word operation on a floating-point register, which
+results in a compile error.
+
+The correct way of implementing `reinterpret_cast` to implement a primpop, but
+that requires a unique implementation for all supported archetectures. The next
+best solution is to write the value from the source register to memory and then
+read it from memory into the destination register and the best way to do that
+is using CMM.
+-}
+
+-- | @'castWord32ToFloat' w@ does a bit-for-bit copy from an integral value
+-- to a floating-point value.
+--
+-- @since 4.10.0.0
+
+{-# INLINE castWord32ToFloat #-}
+castWord32ToFloat :: Word32 -> Float
+castWord32ToFloat (W32# w#) = F# (stgWord32ToFloat w#)
+
+foreign import prim "stg_word32ToFloatzh"
+ stgWord32ToFloat :: Word# -> Float#
+
+
+-- | @'castFloatToWord32' f@ does a bit-for-bit copy from a floating-point value
+-- to an integral value.
+--
+-- @since 4.10.0.0
+
+{-# INLINE castFloatToWord32 #-}
+castFloatToWord32 :: Float -> Word32
+castFloatToWord32 (F# f#) = W32# (stgFloatToWord32 f#)
+
+foreign import prim "stg_floatToWord32zh"
+ stgFloatToWord32 :: Float# -> Word#
+
+
+
+-- | @'castWord64ToDouble' w@ does a bit-for-bit copy from an integral value
+-- to a floating-point value.
+--
+-- @since 4.10.0.0
+
+{-# INLINE castWord64ToDouble #-}
+castWord64ToDouble :: Word64 -> Double
+castWord64ToDouble (W64# w) = D# (stgWord64ToDouble w)
+
+foreign import prim "stg_word64ToDoublezh"
+#if WORD_SIZE_IN_BITS == 64
+ stgWord64ToDouble :: Word# -> Double#
+#else
+ stgWord64ToDouble :: Word64# -> Double#
+#endif
+
+
+-- | @'castFloatToWord32' f@ does a bit-for-bit copy from a floating-point value
+-- to an integral value.
+--
+-- @since 4.10.0.0
+
+{-# INLINE castDoubleToWord64 #-}
+castDoubleToWord64 :: Double -> Word64
+castDoubleToWord64 (D# d#) = W64# (stgDoubleToWord64 d#)
+
+foreign import prim "stg_doubleToWord64zh"
+#if WORD_SIZE_IN_BITS == 64
+ stgDoubleToWord64 :: Double# -> Word#
+#else
+ stgDoubleToWord64 :: Double# -> Word64#
+#endif
diff --git a/libraries/base/cbits/CastFloatWord.cmm b/libraries/base/cbits/CastFloatWord.cmm
new file mode 100644
index 0000000000..18d275f4af
--- /dev/null
+++ b/libraries/base/cbits/CastFloatWord.cmm
@@ -0,0 +1,69 @@
+#include "Cmm.h"
+#include "MachDeps.h"
+
+#if WORD_SIZE_IN_BITS == 64
+#define DOUBLE_SIZE_WDS 1
+#else
+#define DOUBLE_SIZE_WDS 2
+#endif
+
+stg_word64ToDoublezh(I64 w)
+{
+ D_ d;
+ P_ ptr;
+
+ STK_CHK_GEN_N (DOUBLE_SIZE_WDS);
+
+ reserve DOUBLE_SIZE_WDS = ptr {
+ I64[ptr] = w;
+ d = D_[ptr];
+ }
+
+ return (d);
+}
+
+stg_doubleToWord64zh(D_ d)
+{
+ I64 w;
+ P_ ptr;
+
+ STK_CHK_GEN_N (DOUBLE_SIZE_WDS);
+
+ reserve DOUBLE_SIZE_WDS = ptr {
+ D_[ptr] = d;
+ w = I64[ptr];
+ }
+
+ return (w);
+}
+
+stg_word32ToFloatzh(W_ w)
+{
+ F_ f;
+ P_ ptr;
+
+ STK_CHK_GEN_N (1);
+
+ reserve 1 = ptr {
+ I32[ptr] = %lobits32(w);
+ f = F_[ptr];
+ }
+
+ return (f);
+}
+
+stg_floatToWord32zh(F_ f)
+{
+ W_ w;
+ P_ ptr;
+
+ STK_CHK_GEN_N (1);
+
+ reserve 1 = ptr {
+ F_[ptr] = f;
+ w = TO_W_(I32[ptr]);
+ }
+
+ return (w);
+}
+