Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

6 changed files:

Changes:

  • compiler/GHC/Cmm/Node.hs
    ... ... @@ -417,8 +417,8 @@ instance NonLocal CmmNode where
    417 417
     --------------------------------------------------
    
    418 418
     -- Various helper types
    
    419 419
     
    
    420
    -type CmmActual = CmmExpr
    
    421
    -type CmmFormal = LocalReg
    
    420
    +type CmmActual = CmmExpr  -- ^ Usually used to refer to arguments
    
    421
    +type CmmFormal = LocalReg -- ^ Usually used to refer to result registers.
    
    422 422
     
    
    423 423
     type UpdFrameOffset = ByteOff
    
    424 424
     
    

  • compiler/GHC/CmmToAsm/X86/CodeGen.hs
    ... ... @@ -6714,10 +6714,172 @@ genClz bid width dst src = do
    6714 6714
                            -- W8/W16 cases because the 'MOV' insn already
    
    6715 6715
                            -- took care of implicitly clearing the upper bits
    
    6716 6716
     
    
    6717
    +{-
    
    6718
    +Note [Word-to-float conversion on x86-64]
    
    6719
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    6720
    +CVTSI2SD/CVTSI2SS treat their source as a *signed* integer, so an
    
    6721
    +unsigned Word with the MSB set would yield a negative float.
    
    6722
    +
    
    6723
    +We use a halve-and-double trick:
    
    6724
    +  1. If src < 2^63 (MSB clear): convert directly; the signed and
    
    6725
    +     unsigned interpretations agree.
    
    6726
    +  2. If src >= 2^63 (MSB set):
    
    6727
    +     (a) Compute  tmp = (src `shiftR` 1) .|. (src .&. 1)
    
    6728
    +         which halves src while preserving the LSB as a "round bit".
    
    6729
    +     (b) Convert tmp as a signed integer (its MSB is now clear).
    
    6730
    +     (c) Double the float result.
    
    6731
    +
    
    6732
    +The round bit in step (a) is crucial for correct rounding.  Without
    
    6733
    +it, adjacent even and odd large values would produce the same float.
    
    6734
    +With it, the conversion in step (b) sees the correct rounding
    
    6735
    +information, and doubling in step (c) scales back to the right range.
    
    6736
    +
    
    6737
    +Example (Float64, src = 2^64 - 1 = 0xFFFF_FFFF_FFFF_FFFF):
    
    6738
    +  tmp = 0x7FFF_FFFF_FFFF_FFFF | 1 = 0x7FFF_FFFF_FFFF_FFFF
    
    6739
    +  float64(tmp) rounds to 2^63   ≈ 9.2234e18
    
    6740
    +  2 × 9.2234e18 = 1.8447e19   (= float64(2^64 - 1)) ✓
    
    6741
    +
    
    6742
    +Note [Word-to-float64 conversion on i386]
    
    6743
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    6744
    +On 32-bit x86, StgWord is 32 bits.  CVTSI2SD converts a *signed*
    
    6745
    +32-bit integer, so inputs with the MSB set look negative.
    
    6746
    +
    
    6747
    +Trick: add 2^31 to flip the MSB, convert as signed, then add back 2^31 as a
    
    6748
    +Float64 constant.
    
    6749
    +
    
    6750
    +Let src' = src + 2^31 (mod 2^32):
    
    6751
    +  src in [0, 2^31):   src' in [2^31, 2^32), signed value = src - 2^31.
    
    6752
    +                      CVTSI2SD gives src - 2^31. + 2^31.0  →  src ✓
    
    6753
    +  src = 2^31:         src' = 0 (wraps). CVTSI2SD gives 0.0. + 2^31.0 → 2^31 ✓
    
    6754
    +  src in (2^31, 2^32): src' = src - 2^31 ∈ (0, 2^31), positive.
    
    6755
    +                       CVTSI2SD gives src - 2^31. + 2^31.0  →  src ✓
    
    6756
    +
    
    6757
    +The constant 2^31 is materialised without a memory load: 0x4F000000
    
    6758
    +is the IEEE 754 float32 bit-pattern for 2^31; a MOVD + CVTSS2SD
    
    6759
    +gives the exact float64 value.
    
    6760
    +
    
    6761
    +Note [Word-to-float32 conversion on i386]
    
    6762
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    6763
    +On 32-bit x86, StgWord is 32 bits.  CVTSI2SS converts a *signed*
    
    6764
    +32-bit integer, so values >= 2^31 would convert incorrectly.
    
    6765
    +
    
    6766
    +We split the 32-bit unsigned value into its high and low 16-bit halves
    
    6767
    +and convert each separately:
    
    6768
    +  result = float32(high16) × 65536.0 + float32(low16)
    
    6769
    +
    
    6770
    +Both halves are in [0, 65535], within float32's exact integer range
    
    6771
    +(24-bit mantissa covers integers up to 2^24 = 16777216 > 65535).
    
    6772
    +Multiplying by 65536.0 = 2^16 is exact (no mantissa bits consumed).
    
    6773
    +The final addition rounds to the nearest float32, matching a direct
    
    6774
    +uint32→float32 conversion.
    
    6775
    +
    
    6776
    +The constant 65536.0 (= 0x47800000 in float32 bit-pattern) is loaded
    
    6777
    +via a MOV + MOVD, avoiding a memory load.
    
    6778
    +-}
    
    6779
    +
    
    6717 6780
     genWordToFloat :: BlockId -> Width -> CmmFormal -> CmmActual -> NatM InstrBlock
    
    6718
    -genWordToFloat bid width dst src =
    
    6719
    -  -- TODO: generate assembly instead
    
    6720
    -  genPrimCCall bid (word2FloatLabel width) [dst] [src]
    
    6781
    +genWordToFloat bid width dst src = do
    
    6782
    +  is32Bit <- is32BitPlatform
    
    6783
    +  platform <- getPlatform
    
    6784
    +
    
    6785
    +  let srcFormat = intFormat $ cmmExprWidth platform src
    
    6786
    +  let dst_r = getLocalRegReg dst
    
    6787
    +  let conv = case width of
    
    6788
    +              W64 -> CVTSI2SD
    
    6789
    +              W32 -> CVTSI2SS
    
    6790
    +              _ -> pprPanic "genWordToFloat: unsupported width" (ppr width)
    
    6791
    +  let dstFormat = floatFormat width
    
    6792
    +
    
    6793
    +  (src_r, code_src)  <- getSomeReg src
    
    6794
    +
    
    6795
    +  if is32Bit
    
    6796
    +    then case (srcFormat, width) of
    
    6797
    +      (II32, W64) -> do
    
    6798
    +        -- See Note [Word-to-float64 conversion on i386]
    
    6799
    +        cst_r  <- getNewRegNat srcFormat
    
    6800
    +        cst_v  <- getNewRegNat dstFormat
    
    6801
    +        flip_r <- getNewRegNat srcFormat
    
    6802
    +        return $ code_src `appOL` toOL
    
    6803
    +          [ MOV srcFormat (OpImm (ImmInt 0x4F000000)) (OpReg cst_r)         -- load the constant
    
    6804
    +          , MOVD srcFormat (floatFormat W32) (OpReg cst_r) (OpReg cst_v)
    
    6805
    +          , CVTSS2SD cst_v cst_v
    
    6806
    +          , MOV srcFormat (OpReg src_r) (OpReg flip_r)                        -- copy src (modified below)
    
    6807
    +          , ADD srcFormat (OpImm $ ImmInteger 0x80000000) (OpReg flip_r)      -- flip_r = flip MSB(src)
    
    6808
    +          -- XOR dst_r with itself to avoid a false dependency: CVTSI2SD
    
    6809
    +          -- (SSE2) only writes the lower 64 bits of the destination XMM
    
    6810
    +          -- register, leaving the upper bits unchanged. That creates a
    
    6811
    +          -- dependency on the old value of dst_r. Zeroing it first breaks
    
    6812
    +          -- the dependency chain.
    
    6813
    +          , XOR dstFormat (OpReg dst_r) (OpReg dst_r)
    
    6814
    +          , conv srcFormat (OpReg flip_r) dst_r
    
    6815
    +          , ADD dstFormat (OpReg cst_v) (OpReg dst_r) -- +2147483648.0
    
    6816
    +          ]
    
    6817
    +      (II32, W32) -> do
    
    6818
    +        -- See Note [Word-to-float32 conversion on i386]
    
    6819
    +        tmp_v  <- getNewRegNat dstFormat
    
    6820
    +        cst_v  <- getNewRegNat dstFormat
    
    6821
    +        cst_r  <- getNewRegNat srcFormat
    
    6822
    +        high_r <- getNewRegNat srcFormat
    
    6823
    +        low_r  <- getNewRegNat srcFormat
    
    6824
    +        return $ code_src `appOL` toOL
    
    6825
    +          [ MOV srcFormat (OpImm (ImmInt 0x47800000)) (OpReg cst_r) -- load the constant
    
    6826
    +          , MOVD srcFormat dstFormat (OpReg cst_r) (OpReg cst_v)
    
    6827
    +          , MOVZxL II16 (OpReg src_r) (OpReg low_r)                  -- low_r   = low 16 bits
    
    6828
    +          , MOV srcFormat (OpReg src_r) (OpReg high_r)               -- copy src (modified below)
    
    6829
    +          , SHR srcFormat (OpImm $ ImmInt 16) (OpReg high_r)         -- high_r  = high 16 bits
    
    6830
    +          , conv srcFormat (OpReg high_r) dst_r                      -- dst_r = float(high)
    
    6831
    +          , MUL dstFormat (OpReg cst_v) (OpReg dst_r)                -- dst_r = float(high) * 65536.0
    
    6832
    +          -- XOR tmp_v to avoid a false dependency on its previous value
    
    6833
    +          -- before the CVTSI2SS below (same reasoning as in the W64 case).
    
    6834
    +          , XOR dstFormat (OpReg tmp_v) (OpReg tmp_v)
    
    6835
    +          , conv srcFormat (OpReg low_r) tmp_v               -- tmp_v = float(low)
    
    6836
    +          , ADD dstFormat (OpReg tmp_v) (OpReg dst_r)        -- dst_r = float(high)*65536.0 + float(low)
    
    6837
    +          ]
    
    6838
    +      _           -> panic ("genWordToFloat: unsupported source operand format: " ++ show srcFormat)
    
    6839
    +    else do
    
    6840
    +      -- See Note [Word-to-float conversion on x86-64]
    
    6841
    +      half_r  <- getNewRegNat srcFormat
    
    6842
    +      round_r <- getNewRegNat srcFormat
    
    6843
    +
    
    6844
    +      lblLarge  <- getBlockIdNat
    
    6845
    +      lblSmall  <- getBlockIdNat
    
    6846
    +      lblAfter  <- getBlockIdNat
    
    6847
    +
    
    6848
    +      -- We're building a diamond CFG:
    
    6849
    +      --   bid -> lblSmall -> lblAfter -> origSucc
    
    6850
    +      --       \-> lblLarge ->/
    
    6851
    +      -- addImmediateSuccessorNat moves bid's original successor to lblAfter,
    
    6852
    +      -- then we fix up the other edges.
    
    6853
    +      addImmediateSuccessorNat bid lblAfter
    
    6854
    +      -- Small values (MSB clear, i.e. < 2^63) are assumed more common in
    
    6855
    +      -- practice, hence the higher weight on the lblSmall edge.
    
    6856
    +      updateCfgNat ( addWeightEdge bid     lblSmall  100
    
    6857
    +                   . addWeightEdge bid     lblLarge   50
    
    6858
    +                   . addWeightEdge lblSmall lblAfter   1
    
    6859
    +                   . addWeightEdge lblLarge lblAfter   1
    
    6860
    +                   . delEdge bid lblAfter )
    
    6861
    +
    
    6862
    +      return $ appOL (code_src)
    
    6863
    +        $ toOL
    
    6864
    +        [ TEST srcFormat (OpReg src_r) (OpReg src_r)
    
    6865
    +        , JXX NEG lblLarge
    
    6866
    +        -- Adding this label to allow optimizations to either invert condition or just eliminate
    
    6867
    +        , JXX ALWAYS lblSmall
    
    6868
    +        , NEWBLOCK lblSmall
    
    6869
    +        , conv srcFormat (OpReg src_r) dst_r  -- direct conversion for src < 2^63
    
    6870
    +        , JXX ALWAYS lblAfter
    
    6871
    +        , NEWBLOCK lblLarge
    
    6872
    +        -- Halve src, preserving the LSB as a round bit, then convert and double.
    
    6873
    +        , MOV srcFormat (OpReg src_r) (OpReg half_r)
    
    6874
    +        , SHR srcFormat (OpImm $ ImmInt 1) (OpReg half_r)  -- half_r     = src >> 1
    
    6875
    +        , MOV srcFormat (OpReg src_r) (OpReg round_r)      -- copy src (modified below)
    
    6876
    +        , AND srcFormat (OpImm $ ImmInt 1) (OpReg round_r) -- round_r = src & 1  (round bit)
    
    6877
    +        , OR  srcFormat (OpReg round_r) (OpReg half_r)     -- half_r  = (src >> 1) | (src & 1)
    
    6878
    +        , conv srcFormat (OpReg half_r) dst_r
    
    6879
    +        , ADD dstFormat (OpReg dst_r) (OpReg dst_r)        -- double the result
    
    6880
    +        , JXX ALWAYS lblAfter
    
    6881
    +        , NEWBLOCK lblAfter
    
    6882
    +        ]
    
    6721 6883
     
    
    6722 6884
     genAtomicRead :: Width -> MemoryOrdering -> LocalReg -> CmmExpr -> NatM InstrBlock
    
    6723 6885
     genAtomicRead width _mord dst addr = do
    

  • testsuite/tests/codeGen/should_run/Word2Float32.hs
    1 1
     {-# LANGUAGE MagicHash #-}
    
    2 2
     module Main (main) where
    
    3 3
     
    
    4
    -import GHC.Exts (Double(D#), Float(F#), word2Double#, word2Float#)
    
    4
    +import GHC.Exts (Double(D#), Float(F#), Word(W#), word2Double#, word2Float#)
    
    5 5
     
    
    6 6
     main :: IO ()
    
    7 7
     main = do
    
    ... ... @@ -15,3 +15,13 @@ main = do
    15 15
         -- stored in a 32-bit IEEE floating-point value without loss of
    
    16 16
         -- precision
    
    17 17
         print (F# (word2Float# 16777216##))
    
    18
    +
    
    19
    +    -- We also want to check for sane behaviour for cases that lose precision
    
    20
    +    let W# max_word = (maxBound :: Word)
    
    21
    +    print (F# (word2Float# max_word))
    
    22
    +
    
    23
    +    -- 2^31 sits exactly at the MSB boundary exercised by the i386 algorithms
    
    24
    +    -- (see Notes [Word-to-float64 conversion on i386] and
    
    25
    +    -- [Word-to-float32 conversion on i386] in GHC.CmmToAsm.X86.CodeGen)
    
    26
    +    print (D# (word2Double# 2147483648##))
    
    27
    +    print (F# (word2Float# 2147483648##))

  • testsuite/tests/codeGen/should_run/Word2Float32.stdout
    ... ... @@ -2,3 +2,6 @@
    2 2
     4.294967295e9
    
    3 3
     0.0
    
    4 4
     1.6777216e7
    
    5
    +4.2949673e9
    
    6
    +2.147483648e9
    
    7
    +2.1474836e9

  • testsuite/tests/codeGen/should_run/Word2Float64.hs
    1 1
     {-# LANGUAGE MagicHash #-}
    
    2 2
     module Main (main) where
    
    3 3
     
    
    4
    -import GHC.Exts (Double(D#), Float(F#), word2Double#, word2Float#)
    
    4
    +import GHC.Exts (Double(D#), Float(F#), Word(W#), word2Double#, word2Float#)
    
    5 5
     
    
    6 6
     main :: IO ()
    
    7 7
     main = do
    
    ... ... @@ -15,3 +15,14 @@ main = do
    15 15
         -- stored in a 32-bit IEEE floating-point value without loss of
    
    16 16
         -- precision
    
    17 17
         print (F# (word2Float# 16777216##))
    
    18
    +
    
    19
    +    -- We also want to check for sane behaviour for cases that lose precision
    
    20
    +    let W# max_word = (maxBound :: Word)
    
    21
    +    print (F# (word2Float# max_word))
    
    22
    +    print (D# (word2Double# max_word))
    
    23
    +
    
    24
    +    -- 2^63 is the first value that requires the halve-and-double path
    
    25
    +    -- (see Note [Word-to-float conversion on x86-64] in GHC.CmmToAsm.X86.CodeGen)
    
    26
    +    let W# two63 = 0x8000000000000000
    
    27
    +    print (F# (word2Float# two63))
    
    28
    +    print (D# (word2Double# two63))

  • testsuite/tests/codeGen/should_run/Word2Float64.stdout
    ... ... @@ -2,3 +2,7 @@
    2 2
     9.007199254740992e15
    
    3 3
     0.0
    
    4 4
     1.6777216e7
    
    5
    +1.8446744e19
    
    6
    +1.8446744073709552e19
    
    7
    +9.223372e18
    
    8
    +9.223372036854776e18