[Git][ghc/ghc][master] x86 NCG SIMD: Lower packFloatX4#, insertFloatX4# and broadcastFloatX4# to SSE1 instructions

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Sat Nov 16 21:23:27 UTC 2024



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


Commits:
a0e168ec by ARATA Mizuki at 2024-11-16T16:22:40-05:00
x86 NCG SIMD: Lower packFloatX4#, insertFloatX4# and broadcastFloatX4# to SSE1 instructions

Fixes #25441

Co-authored-by: sheaf <sam.derbyshire at gmail.com>

- - - - -


12 changed files:

- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- testsuite/tests/simd/should_run/all.T
- + testsuite/tests/simd/should_run/simd_insert.hs
- + testsuite/tests/simd/should_run/simd_insert.stdout
- + testsuite/tests/simd/should_run/simd_insert_array.hs
- + testsuite/tests/simd/should_run/simd_insert_array.stdout
- + testsuite/tests/simd/should_run/simd_insert_array_baseline.hs
- + testsuite/tests/simd/should_run/simd_insert_array_baseline.stdout
- + testsuite/tests/simd/should_run/simd_insert_baseline.hs
- + testsuite/tests/simd/should_run/simd_insert_baseline.stdout


Changes:

=====================================
compiler/GHC/CmmToAsm/X86/CodeGen.hs
=====================================
@@ -971,7 +971,6 @@ getRegister' _ _ (CmmMachOp mop []) =
   pprPanic "getRegister(x86): nullary MachOp" (text $ show mop)
 
 getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
-    sse4_1 <- sse4_1Enabled
     avx    <- avxEnabled
     case mop of
       MO_F_Neg w  -> sse2NegCode w x
@@ -1068,10 +1067,7 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
         | avx
         -> vector_float_broadcast_avx l w x
         | otherwise
-        -> case w of
-            W32 | not sse4_1
-              -> sorry "32-bit float broadcast requires -msse4 or -fllvm."
-            _ -> vector_float_broadcast_sse l w x
+        -> vector_float_broadcast_sse l w x
       MO_V_Broadcast l w
         -> vector_int_broadcast l w x
 
@@ -1217,6 +1213,7 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
 
         -----------------------
 
+        -- TODO: we could use VBROADCASTSS/SD when AVX2 is available.
         vector_float_broadcast_avx :: Length
                                    -> Width
                                    -> CmmExpr
@@ -1224,11 +1221,8 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
         vector_float_broadcast_avx len w expr = do
           (dst, exp) <- getSomeReg expr
           let fmt = VecFormat len (floatScalarFormat w)
-              code = case w of
-                W64 -> unitOL $ VSHUF fmt (ImmInt 0) (OpReg dst) dst dst
-                _   -> toOL [ INSERTPS fmt (ImmInt 0b00_10_0000) (OpReg dst) dst
-                            , VSHUF fmt (ImmInt 0) (OpReg dst) dst dst ]
-          return $ Fixed fmt dst (exp `appOL` code)
+              code = VSHUF fmt (ImmInt 0) (OpReg dst) dst dst
+          return $ Fixed fmt dst (exp `snocOL` code)
 
         vector_float_broadcast_sse :: Length
                                    -> Width
@@ -1237,11 +1231,8 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
         vector_float_broadcast_sse len w expr = do
           (dst, exp) <- getSomeReg expr
           let fmt = VecFormat len (floatScalarFormat w)
-              code = case w of
-                W64 -> unitOL $ SHUF fmt (ImmInt 0) (OpReg dst) dst
-                _   -> toOL [ INSERTPS fmt (ImmInt 0b00_10_0000) (OpReg dst) dst
-                            , SHUF fmt (ImmInt 0) (OpReg dst) dst ]
-          return $ Fixed fmt dst (exp `appOL` code)
+              code = SHUF fmt (ImmInt 0) (OpReg dst) dst
+          return $ Fixed fmt dst (exp `snocOL` code)
 
         vector_int_broadcast :: Length
                              -> Width
@@ -1801,9 +1792,12 @@ getRegister' platform _is32Bit (CmmMachOp mop [x, y, z]) = do -- ternary MachOps
         -> genFMA3Code l w var x y z
 
       -- Ternary vector operations
-      MO_VF_Insert l W32  | sse4_1 -> vector_float_insert_sse l x y z
-                          | otherwise
-                          -> sorry "FloatX4# operations require either -msse4 or -fllvm"
+      MO_VF_Insert l W32  | l == 4 -> vector_floatx4_insert_sse sse4_1 x y z
+                          | otherwise ->
+         sorry $ "FloatX" ++ show l ++ "# insert operations require -fllvm"
+           -- SIMD NCG TODO:
+           --
+           --   - add support for FloatX8, FloatX16.
       MO_VF_Insert l W64  -> vector_double_insert avx l x y z
       MO_V_Insert l W64   -> vector_int_insert_sse l W64 x y z
 
@@ -1814,31 +1808,59 @@ getRegister' platform _is32Bit (CmmMachOp mop [x, y, z]) = do -- ternary MachOps
     -- SIMD NCG TODO:
     --
     --   - add support for FloatX8, FloatX16.
-    vector_float_insert_sse :: Length
-                            -> CmmExpr
-                            -> CmmExpr
-                            -> CmmExpr
-                            -> NatM Register
-    -- FloatX4
-    vector_float_insert_sse len at 4 vecExpr valExpr (CmmLit (CmmInt offset _))
-      = do
-      (r, exp)    <- getNonClobberedReg valExpr
-      fn          <- getAnyReg vecExpr
-      let fmt      = VecFormat len FmtFloat
-          imm      = litToImm (CmmInt (offset `shiftL` 4) W32)
-          code dst = exp `appOL`
-                     (fn dst) `snocOL`
-                     (INSERTPS fmt imm (OpReg r) dst)
-       in return $ Any fmt code
-    vector_float_insert_sse len _ _ offset
+    vector_floatx4_insert_sse :: Bool
+                              -> CmmExpr
+                              -> CmmExpr
+                              -> CmmExpr
+                              -> NatM Register
+    vector_floatx4_insert_sse sse4_1 vecExpr valExpr (CmmLit (CmmInt offset _))
+      | sse4_1 = do
+        (r, exp)    <- getNonClobberedReg valExpr
+        fn          <- getAnyReg vecExpr
+        let fmt      = VecFormat 4 FmtFloat
+            imm      = litToImm (CmmInt (offset `shiftL` 4) W32)
+            code dst = exp `appOL`
+                      (fn dst) `snocOL`
+                      (INSERTPS fmt imm (OpReg r) dst)
+         in return $ Any fmt code
+      | otherwise = do -- SSE <= 3
+        (r, exp)    <- getNonClobberedReg valExpr
+        fn          <- getAnyReg vecExpr
+        let fmt      = VecFormat 4 FmtFloat
+        tmp <- getNewRegNat fmt
+        let code dst
+              = case offset of
+                  0 -> exp `appOL`
+                      (fn dst) `snocOL`
+                      -- The following MOV compiles to MOVSS instruction and merges two vectors
+                      (MOV fmt (OpReg r) (OpReg dst))  -- dst <- (r[0],dst[1],dst[2],dst[3])
+                  1 -> exp `appOL`
+                      (fn dst) `snocOL`
+                      (MOVU fmt (OpReg dst) (OpReg tmp)) `snocOL`  -- tmp <- dst
+                      (UNPCKL fmt (OpReg r) dst) `snocOL`          -- dst <- (dst[0],r[0],dst[1],r[1])
+                      (SHUF fmt (ImmInt 0xe4) (OpReg tmp) dst)     -- dst <- (dst[0],dst[1],tmp[2],tmp[3])
+                  2 -> exp `appOL`
+                       (fn dst) `snocOL`
+                       (MOVU fmt (OpReg dst) (OpReg tmp)) `snocOL`  -- tmp <- dst
+                       (MOV fmt (OpReg r) (OpReg tmp)) `snocOL`     -- tmp <- (r[0],tmp[1],tmp[2],tmp[3]) with MOVSS
+                       (SHUF fmt (ImmInt 0xc4) (OpReg tmp) dst)     -- dst <- (dst[0],dst[1],tmp[0],tmp[3])
+                  3 -> exp `appOL`
+                       (fn dst) `snocOL`
+                       (MOVU fmt (OpReg dst) (OpReg tmp)) `snocOL`  -- tmp <- dst
+                       (MOV fmt (OpReg r) (OpReg tmp)) `snocOL`     -- tmp <- (r[0],tmp[1],tmp[2],tmp[3]) with MOVSS
+                       (SHUF fmt (ImmInt 0x24) (OpReg tmp) dst)     -- dst <- (dst[0],dst[1],tmp[2],tmp[0])
+                  _ -> panic "MO_VF_Insert FloatX4: unsupported offset"
+         in return $ Any fmt code
+    vector_floatx4_insert_sse _ _ _ offset
       = pprPanic "Unsupported vector insert operation" $
           vcat
-            [ text "FloatX" <> ppr len <> text "#"
+            [ text "FloatX4#"
             , text "offset:" <+> pdoc platform offset ]
 
+
     -- SIMD NCG TODO:
     --
-    --   - add support for FloatX8, FloatX16.
+    --   - add support for DoubleX4#, DoubleX8#.
     vector_double_insert :: Bool
                          -> Length
                          -> CmmExpr
@@ -1857,6 +1879,7 @@ getRegister' platform _is32Bit (CmmMachOp mop [x, y, z]) = do -- ternary MachOps
                   CmmInt 0 _ -> valExp `appOL`
                                 vecExp `snocOL`
                                 (movu (VecFormat 2 FmtDouble) (OpReg vecReg) (OpReg dst)) `snocOL`
+                                -- The following MOV compiles to MOVSD instruction and merges two vectors
                                 (MOV (VecFormat 2 FmtDouble) (OpReg valReg) (OpReg dst))
                   CmmInt 1 _ -> valExp `appOL`
                                 vecExp `snocOL`


=====================================
compiler/GHC/CmmToAsm/X86/Instr.hs
=====================================
@@ -325,6 +325,7 @@ data Instr
         -- | Move two 32-bit floats from the high part of an xmm register
         -- to the low part of another xmm register.
         | MOVHLPS    Format Reg Reg
+        | UNPCKL     Format Operand Reg
         | PUNPCKLQDQ Format Operand Reg
 
         -- Shift
@@ -524,6 +525,8 @@ regUsageOfInstr platform instr
 
     MOVHLPS    fmt src dst
       -> mkRU [mk fmt src] [mk fmt dst]
+    UNPCKL fmt src dst
+      -> mkRU (use_R fmt src [mk fmt dst]) [mk fmt dst]
     PUNPCKLQDQ fmt src dst
       -> mkRU (use_R fmt src [mk fmt dst]) [mk fmt dst]
 
@@ -765,6 +768,8 @@ patchRegsOfInstr platform instr env
 
     MOVHLPS    fmt src dst
       -> MOVHLPS fmt (env src) (env dst)
+    UNPCKL fmt src dst
+      -> UNPCKL fmt (patchOp src) (env dst)
     PUNPCKLQDQ fmt src dst
       -> PUNPCKLQDQ fmt (patchOp src) (env dst)
 


=====================================
compiler/GHC/CmmToAsm/X86/Ppr.hs
=====================================
@@ -1041,6 +1041,8 @@ pprInstr platform i = case i of
 
    MOVHLPS format from to
      -> pprOpReg (text "movhlps") format (OpReg from) to
+   UNPCKL format src dst
+     -> pprFormatOpReg (text "unpckl") format src dst
    PUNPCKLQDQ format from to
      -> pprOpReg (text "punpcklqdq") format from to
 


=====================================
testsuite/tests/simd/should_run/all.T
=====================================
@@ -12,13 +12,18 @@ setTestOpts(
   , when(unregisterised(), skip)
   , when(arch('wasm32'), skip)
   , js_skip
+  ])
+
+test('simd_insert_baseline', [], compile_and_run, [''])
+test('simd_insert_array_baseline', [], compile_and_run, [''])
 
-  # Ensure we set the CPU features we have available.
-  #
-  # This is especially important with the LLVM backend, as LLVM can otherwise
-  # produce ABI-incompatible code, e.g. when compiling usage of YMM registers
-  # with or without -mavx2.
-  , when(have_cpu_feature('sse4_1'), extra_hc_opts('-msse4'))
+# Ensure we set the CPU features we have available.
+#
+# This is especially important with the LLVM backend, as LLVM can otherwise
+# produce ABI-incompatible code, e.g. when compiling usage of YMM registers
+# with or without -mavx2.
+setTestOpts(
+  [ when(have_cpu_feature('sse4_1'), extra_hc_opts('-msse4'))
   , when(have_cpu_feature('avx'), extra_hc_opts('-mavx'))
   , when(have_cpu_feature('avx2'), extra_hc_opts('-mavx2'))
   , when(have_cpu_feature('avx512f'), extra_hc_opts('-mavx512f'))
@@ -55,6 +60,9 @@ test('simd014',
         # register on non-x86 architectures.
      compile_and_run, ['simd014Cmm.cmm'])
 
+test('simd_insert', [], compile_and_run, [''])
+test('simd_insert_array', [], compile_and_run, [''])
+
 test('T22187', [],compile,[''])
 test('T22187_run', [],compile_and_run,[''])
 test('T25062_V16', [], compile_and_run, [''])


=====================================
testsuite/tests/simd/should_run/simd_insert.hs
=====================================
@@ -0,0 +1,37 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+import GHC.Exts
+
+unpackFloatX4 :: FloatX4# -> (Float, Float, Float, Float)
+unpackFloatX4 v = case unpackFloatX4# v of
+  (# a0, a1, a2, a3 #) -> (F# a0, F# a1, F# a2, F# a3)
+
+unpackDoubleX2 :: DoubleX2# -> (Double, Double)
+unpackDoubleX2 v = case unpackDoubleX2# v of
+  (# a0, a1 #) -> (D# a0, D# a1)
+
+testFloatX4 :: IO ()
+testFloatX4 = do
+  let v = packFloatX4# (# 0.1#, 1.0#, 2.0#, 3.0# #)
+  print $ unpackFloatX4 v
+  let w = insertFloatX4# v 7.0# 0#
+  print $ unpackFloatX4 w
+  let x = insertFloatX4# v 7.0# 1#
+  print $ unpackFloatX4 x
+  let y = insertFloatX4# v 7.0# 2#
+  print $ unpackFloatX4 y
+  let z = insertFloatX4# v 7.0# 3#
+  print $ unpackFloatX4 z
+
+testDoubleX2 :: IO ()
+testDoubleX2 = do
+  let v = packDoubleX2# (# 0.1##, 1.0## #)
+  print $ unpackDoubleX2 v
+  let w = insertDoubleX2# v 7.0## 0#
+  print $ unpackDoubleX2 w
+  let x = insertDoubleX2# v 7.0## 1#
+  print $ unpackDoubleX2 x
+
+main :: IO ()
+main = do
+  testFloatX4
+  testDoubleX2


=====================================
testsuite/tests/simd/should_run/simd_insert.stdout
=====================================
@@ -0,0 +1,8 @@
+(0.1,1.0,2.0,3.0)
+(7.0,1.0,2.0,3.0)
+(0.1,7.0,2.0,3.0)
+(0.1,1.0,7.0,3.0)
+(0.1,1.0,2.0,7.0)
+(0.1,1.0)
+(7.0,1.0)
+(0.1,7.0)


=====================================
testsuite/tests/simd/should_run/simd_insert_array.hs
=====================================
@@ -0,0 +1,49 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+import Control.Monad
+import Data.Array.Base
+import GHC.Exts
+
+unpackFloatX4 :: FloatX4# -> (Float, Float, Float, Float)
+unpackFloatX4 v = case unpackFloatX4# v of
+  (# a0, a1, a2, a3 #) -> (F# a0, F# a1, F# a2, F# a3)
+
+unpackDoubleX2 :: DoubleX2# -> (Double, Double)
+unpackDoubleX2 v = case unpackDoubleX2# v of
+  (# a0, a1 #) -> (D# a0, D# a1)
+
+indexFloatArrayAsFloatX4 :: UArray Int Float -> Int -> FloatX4#
+indexFloatArrayAsFloatX4 (UArray l u n ba) i = case i - l of I# i# -> indexFloatArrayAsFloatX4# ba i#
+
+indexDoubleArrayAsDoubleX2 :: UArray Int Double -> Int -> DoubleX2#
+indexDoubleArrayAsDoubleX2 (UArray l u n ba) i = case i - l of I# i# -> indexDoubleArrayAsDoubleX2# ba i#
+
+someFloatArray :: UArray Int Float
+someFloatArray = listArray (0, 7) [111.0, 222.0, 333.0, 444.0, 555.0, 666.0, 777.0, 888.0]
+
+someDoubleArray :: UArray Int Double
+someDoubleArray = listArray (0, 7) [111.0, 222.0, 333.0, 444.0, 555.0, 666.0, 777.0, 888.0]
+
+testFloatX4 :: IO ()
+testFloatX4 = forM_ [0,4] $ \i -> do
+  let v = indexFloatArrayAsFloatX4 someFloatArray i
+  let w = insertFloatX4# v 123.45# 0#
+  print $ unpackFloatX4 w
+  let x = insertFloatX4# v 123.45# 1#
+  print $ unpackFloatX4 x
+  let y = insertFloatX4# v 123.45# 2#
+  print $ unpackFloatX4 y
+  let z = insertFloatX4# v 123.45# 3#
+  print $ unpackFloatX4 z
+
+testDoubleX2 :: IO ()
+testDoubleX2 = forM_ [0,2,4,6] $ \i -> do
+  let v = indexDoubleArrayAsDoubleX2 someDoubleArray i
+  let w = insertDoubleX2# v 123.45## 0#
+  print $ unpackDoubleX2 w
+  let x = insertDoubleX2# v 123.45## 1#
+  print $ unpackDoubleX2 x
+
+main :: IO ()
+main = do
+  testFloatX4
+  testDoubleX2


=====================================
testsuite/tests/simd/should_run/simd_insert_array.stdout
=====================================
@@ -0,0 +1,16 @@
+(123.45,222.0,333.0,444.0)
+(111.0,123.45,333.0,444.0)
+(111.0,222.0,123.45,444.0)
+(111.0,222.0,333.0,123.45)
+(123.45,666.0,777.0,888.0)
+(555.0,123.45,777.0,888.0)
+(555.0,666.0,123.45,888.0)
+(555.0,666.0,777.0,123.45)
+(123.45,222.0)
+(111.0,123.45)
+(123.45,444.0)
+(333.0,123.45)
+(123.45,666.0)
+(555.0,123.45)
+(123.45,888.0)
+(777.0,123.45)


=====================================
testsuite/tests/simd/should_run/simd_insert_array_baseline.hs
=====================================
@@ -0,0 +1,49 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+import Control.Monad
+import Data.Array.Base
+import GHC.Exts
+
+unpackFloatX4 :: FloatX4# -> (Float, Float, Float, Float)
+unpackFloatX4 v = case unpackFloatX4# v of
+  (# a0, a1, a2, a3 #) -> (F# a0, F# a1, F# a2, F# a3)
+
+unpackDoubleX2 :: DoubleX2# -> (Double, Double)
+unpackDoubleX2 v = case unpackDoubleX2# v of
+  (# a0, a1 #) -> (D# a0, D# a1)
+
+indexFloatArrayAsFloatX4 :: UArray Int Float -> Int -> FloatX4#
+indexFloatArrayAsFloatX4 (UArray l u n ba) i = case i - l of I# i# -> indexFloatArrayAsFloatX4# ba i#
+
+indexDoubleArrayAsDoubleX2 :: UArray Int Double -> Int -> DoubleX2#
+indexDoubleArrayAsDoubleX2 (UArray l u n ba) i = case i - l of I# i# -> indexDoubleArrayAsDoubleX2# ba i#
+
+someFloatArray :: UArray Int Float
+someFloatArray = listArray (0, 7) [111.0, 222.0, 333.0, 444.0, 555.0, 666.0, 777.0, 888.0]
+
+someDoubleArray :: UArray Int Double
+someDoubleArray = listArray (0, 7) [111.0, 222.0, 333.0, 444.0, 555.0, 666.0, 777.0, 888.0]
+
+testFloatX4 :: IO ()
+testFloatX4 = forM_ [0,4] $ \i -> do
+  let v = indexFloatArrayAsFloatX4 someFloatArray i
+  let w = insertFloatX4# v 123.45# 0#
+  print $ unpackFloatX4 w
+  let x = insertFloatX4# v 123.45# 1#
+  print $ unpackFloatX4 x
+  let y = insertFloatX4# v 123.45# 2#
+  print $ unpackFloatX4 y
+  let z = insertFloatX4# v 123.45# 3#
+  print $ unpackFloatX4 z
+
+testDoubleX2 :: IO ()
+testDoubleX2 = forM_ [0,2,4,6] $ \i -> do
+  let v = indexDoubleArrayAsDoubleX2 someDoubleArray i
+  let w = insertDoubleX2# v 123.45## 0#
+  print $ unpackDoubleX2 w
+  let x = insertDoubleX2# v 123.45## 1#
+  print $ unpackDoubleX2 x
+
+main :: IO ()
+main = do
+  testFloatX4
+  testDoubleX2


=====================================
testsuite/tests/simd/should_run/simd_insert_array_baseline.stdout
=====================================
@@ -0,0 +1,16 @@
+(123.45,222.0,333.0,444.0)
+(111.0,123.45,333.0,444.0)
+(111.0,222.0,123.45,444.0)
+(111.0,222.0,333.0,123.45)
+(123.45,666.0,777.0,888.0)
+(555.0,123.45,777.0,888.0)
+(555.0,666.0,123.45,888.0)
+(555.0,666.0,777.0,123.45)
+(123.45,222.0)
+(111.0,123.45)
+(123.45,444.0)
+(333.0,123.45)
+(123.45,666.0)
+(555.0,123.45)
+(123.45,888.0)
+(777.0,123.45)


=====================================
testsuite/tests/simd/should_run/simd_insert_baseline.hs
=====================================
@@ -0,0 +1,37 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+import GHC.Exts
+
+unpackFloatX4 :: FloatX4# -> (Float, Float, Float, Float)
+unpackFloatX4 v = case unpackFloatX4# v of
+  (# a0, a1, a2, a3 #) -> (F# a0, F# a1, F# a2, F# a3)
+
+unpackDoubleX2 :: DoubleX2# -> (Double, Double)
+unpackDoubleX2 v = case unpackDoubleX2# v of
+  (# a0, a1 #) -> (D# a0, D# a1)
+
+testFloatX4 :: IO ()
+testFloatX4 = do
+  let v = packFloatX4# (# 0.1#, 1.0#, 2.0#, 3.0# #)
+  print $ unpackFloatX4 v
+  let w = insertFloatX4# v 7.0# 0#
+  print $ unpackFloatX4 w
+  let x = insertFloatX4# v 7.0# 1#
+  print $ unpackFloatX4 x
+  let y = insertFloatX4# v 7.0# 2#
+  print $ unpackFloatX4 y
+  let z = insertFloatX4# v 7.0# 3#
+  print $ unpackFloatX4 z
+
+testDoubleX2 :: IO ()
+testDoubleX2 = do
+  let v = packDoubleX2# (# 0.1##, 1.0## #)
+  print $ unpackDoubleX2 v
+  let w = insertDoubleX2# v 7.0## 0#
+  print $ unpackDoubleX2 w
+  let x = insertDoubleX2# v 7.0## 1#
+  print $ unpackDoubleX2 x
+
+main :: IO ()
+main = do
+  testFloatX4
+  testDoubleX2


=====================================
testsuite/tests/simd/should_run/simd_insert_baseline.stdout
=====================================
@@ -0,0 +1,8 @@
+(0.1,1.0,2.0,3.0)
+(7.0,1.0,2.0,3.0)
+(0.1,7.0,2.0,3.0)
+(0.1,1.0,7.0,3.0)
+(0.1,1.0,2.0,7.0)
+(0.1,1.0)
+(7.0,1.0)
+(0.1,7.0)



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a0e168ec0b6f18ffeddaf8a5dfc68e84563630b8

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a0e168ec0b6f18ffeddaf8a5dfc68e84563630b8
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20241116/780e7ad3/attachment-0001.html>


More information about the ghc-commits mailing list