Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC

Commits:

12 changed files:

Changes:

  • .gitlab/generate-ci/gen_ci.hs
    ... ... @@ -445,7 +445,7 @@ opsysVariables _ FreeBSD14 = mconcat
    445 445
         -- Prefer to use the system's clang-based toolchain and not gcc
    
    446 446
       , "CC" =: "cc"
    
    447 447
       , "CXX" =: "c++"
    
    448
    -  , "FETCH_GHC_VERSION" =: "9.10.1"
    
    448
    +  , "FETCH_GHC_VERSION" =: "9.10.3"
    
    449 449
       , "CABAL_INSTALL_VERSION" =: "3.14.2.0"
    
    450 450
       ]
    
    451 451
     opsysVariables arch (Linux distro) = distroVariables arch distro
    

  • .gitlab/jobs.yaml
    ... ... @@ -1721,7 +1721,7 @@
    1721 1721
           "CC": "cc",
    
    1722 1722
           "CONFIGURE_ARGS": "--with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib --with-system-libffi --with-ffi-includes=/usr/local/include --with-ffi-libraries=/usr/local/lib --with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --enable-strict-ghc-toolchain-check",
    
    1723 1723
           "CXX": "c++",
    
    1724
    -      "FETCH_GHC_VERSION": "9.10.1",
    
    1724
    +      "FETCH_GHC_VERSION": "9.10.3",
    
    1725 1725
           "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    1726 1726
           "RUNTEST_ARGS": "",
    
    1727 1727
           "TEST_ENV": "x86_64-freebsd14-validate",
    
    ... ... @@ -4543,7 +4543,7 @@
    4543 4543
           "CC": "cc",
    
    4544 4544
           "CONFIGURE_ARGS": "--with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib --with-system-libffi --with-ffi-includes=/usr/local/include --with-ffi-libraries=/usr/local/lib --with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --enable-strict-ghc-toolchain-check",
    
    4545 4545
           "CXX": "c++",
    
    4546
    -      "FETCH_GHC_VERSION": "9.10.1",
    
    4546
    +      "FETCH_GHC_VERSION": "9.10.3",
    
    4547 4547
           "IGNORE_PERF_FAILURES": "all",
    
    4548 4548
           "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    4549 4549
           "RUNTEST_ARGS": "",
    
    ... ... @@ -5643,7 +5643,7 @@
    5643 5643
           "CC": "cc",
    
    5644 5644
           "CONFIGURE_ARGS": "--with-iconv-includes=/usr/local/include --with-iconv-libraries=/usr/local/lib --with-system-libffi --with-ffi-includes=/usr/local/include --with-ffi-libraries=/usr/local/lib --with-gmp-includes=/usr/local/include --with-gmp-libraries=/usr/local/lib --enable-strict-ghc-toolchain-check",
    
    5645 5645
           "CXX": "c++",
    
    5646
    -      "FETCH_GHC_VERSION": "9.10.1",
    
    5646
    +      "FETCH_GHC_VERSION": "9.10.3",
    
    5647 5647
           "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check",
    
    5648 5648
           "RUNTEST_ARGS": "",
    
    5649 5649
           "TEST_ENV": "x86_64-freebsd14-validate"
    

  • .gitlab/merge_request_templates/Default.md
    1
    +
    
    2
    +<!--
    
    1 3
     Thank you for your contribution to GHC!
    
    2 4
     
    
    3
    -**Please read the checklist below to make sure your contribution fulfills these
    
    4
    -expectations. Also please answer the following question in your MR description:**
    
    5
    -
    
    6
    -**Where is the key part of this patch? That is, what should reviewers look at first?**
    
    7
    -
    
    8
    -Please take a few moments to address the following points:
    
    9
    -
    
    10
    - * [ ] if your MR touches `base` (or touches parts of `ghc-internal` used
    
    11
    -   or re-exported by `base`) more substantially than just amending comments
    
    12
    -   or documentation, you likely need to raise a
    
    13
    -   [CLC proposal](https://github.com/haskell/core-libraries-committee#base-package)
    
    14
    -   before merging it.
    
    15
    - * [ ] if your MR may break existing programs (e.g. causes the
    
    16
    -   compiler to reject programs), please describe the expected breakage and add
    
    17
    -   the ~"user-facing" label. This will run ghc/head.hackage> to characterise
    
    18
    -   the effect of your change on Hackage.
    
    19
    - * [ ] ensure that your commits are either individually buildable or squashed
    
    20
    - * [ ] ensure that your commit messages describe *what they do*
    
    21
    -   (referring to tickets using `#NNNN` syntax when appropriate)
    
    22
    - * [ ] have added source comments describing your change. For larger changes you
    
    23
    -   likely should add a [Note][notes] and cross-reference it from the relevant
    
    24
    -   places.
    
    25
    - * [ ] add a [testcase to the testsuite][adding test].
    
    26
    - * [ ] updates the users guide if applicable
    
    27
    - * [ ] add a changelog entry in `changelog.d/` for user-facing changes (see [changelog guide][changelog]).
    
    28
    -   If this MR does not need a changelog entry, apply the ~"no-changelog" label.
    
    5
    +Please read the checklist below to make sure your contribution fulfills these
    
    6
    +expectations.
    
    29 7
     
    
    30 8
     If you have any questions don't hesitate to open your merge request and inquire
    
    31 9
     in a comment. If your patch isn't quite done yet please do add prefix your MR
    
    32
    -title with `WIP:`.
    
    10
    +title with Draft:
    
    11
    +
    
    12
    +To make your contribution experience as smooth as possible, also check out
    
    13
    +https://gitlab.haskell.org/ghc/ghc/-/wikis/Contributing-a-Patch
    
    14
    +--> 
    
    15
    +
    
    16
    +## Changes contained in this patch
    
    17
    +<!-- Where is the key part of this patch? That is, what should reviewers look at first? -->
    
    18
    +
    
    19
    +
    
    20
    +## MR Checklist
    
    21
    +<!-- Please take a few moments to address the following points: -->
    
    22
    +
    
    23
    +- [ ] This MR solves the problem described in the following issue: <!-- issue number here (please open a new issue if there isn't one) -->
    
    24
    +- [ ] A changelog entry was added in `changelog.d/` for user-facing changes (see [changelog guide][changelog]).
    
    25
    +      If this MR does not need a changelog entry, the ~"no-changelog" label was applied.
    
    26
    +- [ ] This MR does not make any significant changes to `base`, or it has an accompanying [CLC proposal](https://github.com/haskell/core-libraries-committee#base-package).
    
    27
    +- [ ] If this MR has the potential to break user programs, the ~"user-facing" label was applied to 
    
    28
    +      test against head.hackage.
    
    29
    +- [ ] All commits are either individually buildable or squashed.
    
    30
    +- [ ] Commit messages describe *what they do*, referring to tickets using `#NNNNN` syntax.
    
    31
    +- [ ] Source comments describing the change were added. For larger changes [notes][notes] and 
    
    32
    +      cross-references from the relevant places were added (as applicable).
    
    33
    +- [ ] [Testcases to the testsuite][adding test] were added (as applicable).
    
    34
    +- [ ] The users guide was updated (as applicable).
    
    33 35
     
    
    36
    +<!--
    
    34 37
     By default a minimal validation pipeline is run on each merge request, the ~full-ci
    
    35 38
     label can be applied to perform additional validation checks if your MR affects a more
    
    36 39
     unusual configuration.
    
    37 40
     
    
    38
    -Once your change is ready please remove the `WIP:` tag and wait for review. If
    
    41
    +Once your change is ready please remove the `Draft:` tag and wait for review. If
    
    39 42
     no one has offered a review in a few days then please leave a comment mentioning
    
    40 43
     @triagers and apply the ~"Blocked on Review" label.
    
    44
    +-->
    
    41 45
     
    
    42 46
     [notes]: https://gitlab.haskell.org/ghc/ghc/wikis/commentary/coding-style#comments-in-the-source-code
    
    43 47
     [adding test]: https://gitlab.haskell.org/ghc/ghc/wikis/building/running-tests/adding
    

  • changelog.d/binary-array-no-list
    1
    +section: compiler
    
    2
    +synopsis: Reduce allocations when (de)serialising `Array` in the `ghc` library.
    
    3
    +issues: #27109
    
    4
    +mrs: !15805
    
    5
    +
    
    6
    +description: {
    
    7
    +  The `ghc` library's `Binary` instance for `Array` was changed to
    
    8
    +  avoid allocating an intermediate list and to omit a redundant length
    
    9
    +  field during (de)serialisation.
    
    10
    +
    
    11
    +  This should only affect the `ghc` library's (de)serialisation code paths,
    
    12
    +  primarily when parsing HIE files and bytecode objects.
    
    13
    +}

  • compiler/GHC/Data/FastString.hs
    ... ... @@ -139,6 +139,7 @@ import Foreign.C
    139 139
     import System.IO
    
    140 140
     import Data.Data
    
    141 141
     import Data.IORef
    
    142
    +import qualified Data.List.NonEmpty as NE
    
    142 143
     import Data.Semigroup as Semi
    
    143 144
     
    
    144 145
     import Foreign
    
    ... ... @@ -232,6 +233,7 @@ instance IsString FastString where
    232 233
     
    
    233 234
     instance Semi.Semigroup FastString where
    
    234 235
         (<>) = appendFS
    
    236
    +    sconcat = concatFS . NE.toList
    
    235 237
     
    
    236 238
     instance Monoid FastString where
    
    237 239
         mempty = nilFS
    
    ... ... @@ -619,6 +621,42 @@ unpackFS fs = utf8DecodeShortByteString $ fs_sbs fs
    619 621
     zEncodeFS :: FastString -> FastZString
    
    620 622
     zEncodeFS fs = fs_zenc fs
    
    621 623
     
    
    624
    +-- Sometimes an `appendFS` operand is temporarily constructed, and we
    
    625
    +-- should avoid retaining the unused `FastString` operand in the
    
    626
    +-- table. The RULES below mitigate the issue by concatenating the
    
    627
    +-- `ShortByteString`s instead when an operand is `fsLit` or
    
    628
    +-- `mkFastString`, which cover most such `appendFS` use cases. See
    
    629
    +-- #27205.
    
    630
    +
    
    631
    +{-# RULES
    
    632
    +"appendFS/fsLit y" forall x y.
    
    633
    +  appendFS x (fsLit y) =
    
    634
    +    mkFastStringShortByteString $
    
    635
    +      fs_sbs x Semi.<> utf8EncodeShortByteString y
    
    636
    +  #-}
    
    637
    +
    
    638
    +{-# RULES
    
    639
    +"appendFS/fsLit x" forall x y.
    
    640
    +  appendFS (fsLit x) y =
    
    641
    +    mkFastStringShortByteString $
    
    642
    +      utf8EncodeShortByteString x Semi.<> fs_sbs y
    
    643
    +  #-}
    
    644
    +
    
    645
    +{-# RULES
    
    646
    +"appendFS/mkFastString y" forall x y.
    
    647
    +  appendFS x (mkFastString y) =
    
    648
    +    mkFastStringShortByteString $
    
    649
    +      fs_sbs x Semi.<> utf8EncodeShortByteString y
    
    650
    +  #-}
    
    651
    +
    
    652
    +{-# RULES
    
    653
    +"appendFS/mkFastString x" forall x y.
    
    654
    +  appendFS (mkFastString x) y =
    
    655
    +    mkFastStringShortByteString $
    
    656
    +      utf8EncodeShortByteString x Semi.<> fs_sbs y
    
    657
    +  #-}
    
    658
    +
    
    659
    +{-# INLINE[1] appendFS #-}
    
    622 660
     appendFS :: FastString -> FastString -> FastString
    
    623 661
     appendFS fs1 fs2 = mkFastStringShortByteString
    
    624 662
                      $ (Semi.<>) (fs_sbs fs1) (fs_sbs fs2)
    

  • compiler/GHC/Utils/Binary.hs
    ... ... @@ -142,6 +142,8 @@ import Control.DeepSeq
    142 142
     import Control.Monad            ( when, (<$!>), unless, forM_, void )
    
    143 143
     import Foreign hiding (bit, setBit, clearBit, shiftL, shiftR, void)
    
    144 144
     import Data.Array
    
    145
    +import Data.Array.Base (unsafeFreezeIOArray)
    
    146
    +import Data.Array.IArray (traverseArray_)
    
    145 147
     import Data.Array.IO
    
    146 148
     import Data.Array.Unsafe
    
    147 149
     import qualified Data.Binary as Binary
    
    ... ... @@ -970,11 +972,12 @@ instance Binary a => Binary (NonEmpty a) where
    970 972
     instance (Ix a, Binary a, Binary b) => Binary (Array a b) where
    
    971 973
         put_ bh arr = do
    
    972 974
             put_ bh $ bounds arr
    
    973
    -        put_ bh $ elems arr
    
    975
    +        traverseArray_ (put_ bh) arr
    
    976
    +
    
    974 977
         get bh = do
    
    975
    -        bounds <- get bh
    
    976
    -        xs <- get bh
    
    977
    -        return $ listArray bounds xs
    
    978
    +        (l, u) <- get bh
    
    979
    +        marr <- newGenArray (l, u) $ \_ -> get bh
    
    980
    +        unsafeFreezeIOArray marr
    
    978 981
     
    
    979 982
     instance Binary a => Binary (SmallArray a) where
    
    980 983
         put_ bh sa = do
    

  • testsuite/driver/testlib.py
    ... ... @@ -13,6 +13,7 @@ import time
    13 13
     import datetime
    
    14 14
     import copy
    
    15 15
     import glob
    
    16
    +import random
    
    16 17
     import sys
    
    17 18
     from math import ceil, trunc, floor, log
    
    18 19
     from pathlib import Path, PurePath
    
    ... ... @@ -648,6 +649,11 @@ def extra_files(files):
    648 649
     def _extra_files(name, opts, files):
    
    649 650
         opts.extra_files.extend(files)
    
    650 651
     
    
    652
    +def mini_quickcheck(name, opts):
    
    653
    +    miniqc = os.path.relpath(config.top / 'tests' / 'MiniQuickCheck.hs', opts.srcdir)
    
    654
    +    opts.extra_files.extend([miniqc])
    
    655
    +    opts.extra_run_opts += ' ' + str(random.getrandbits(64))
    
    656
    +
    
    651 657
     # Record the size of a specific file
    
    652 658
     def collect_size ( deviation, path ):
    
    653 659
         return collect_size_func(deviation, lambda: path)
    

  • testsuite/tests/MiniQuickCheck.hs
    1
    +{-# LANGUAGE DataKinds                  #-}
    
    2
    +{-# LANGUAGE DerivingStrategies         #-}
    
    3
    +{-# LANGUAGE GeneralisedNewtypeDeriving #-}
    
    4
    +{-# LANGUAGE RecordWildCards            #-}
    
    5
    +{-# LANGUAGE TypeFamilies               #-}
    
    6
    +
    
    7
    +-- | A minimal QuickCheck-like property testing framework for use in the GHC
    
    8
    +-- test suite.
    
    9
    +--
    
    10
    +-- We vendor this package to avoid depending on the real QuickCheck package,
    
    11
    +-- as the latter (or one of its dependencies) may not build with the GHC version
    
    12
    +-- being tested.
    
    13
    +module MiniQuickCheck
    
    14
    +  ( -- * QuickCheck generator
    
    15
    +    Gen(..)
    
    16
    +
    
    17
    +    -- * QuickCheck typeclasses
    
    18
    +  , Arbitrary(..)
    
    19
    +  , IsProperty(..)
    
    20
    +
    
    21
    +    -- * QuickCheck properties
    
    22
    +  , PropertyCheck(..)
    
    23
    +  , PropertyTestArg(..)
    
    24
    +  , Property(..)
    
    25
    +  , forAll
    
    26
    +  , (===)
    
    27
    +  , propertyCompare
    
    28
    +  , propertyAnd
    
    29
    +  , getCheck
    
    30
    +
    
    31
    +    -- * QuickCheck test tree
    
    32
    +  , Test(..)
    
    33
    +
    
    34
    +    -- * Running QuickCheck tests
    
    35
    +  , Result(..)
    
    36
    +  , Iterations(..)
    
    37
    +  , runTestsMain
    
    38
    +  , runTests
    
    39
    +  , runTestInternal
    
    40
    +
    
    41
    +    -- * QuickCheck primitive generators
    
    42
    +  , arbitraryInt64
    
    43
    +  , arbitraryWord64
    
    44
    +  , integralDownsize
    
    45
    +  , wordDownsize
    
    46
    +
    
    47
    +    -- * QuickCheck newtypes
    
    48
    +  , NonZero(..)
    
    49
    +  , nonZero
    
    50
    +  , BoundedShiftAmount(..)
    
    51
    +  , BoundedBy(..)
    
    52
    +  ) where
    
    53
    +
    
    54
    +-- base
    
    55
    +import Control.Monad.IO.Class
    
    56
    +  ( liftIO )
    
    57
    +import Data.Bits
    
    58
    +  ( (.|.), shiftL, shiftR
    
    59
    +  , FiniteBits, finiteBitSize
    
    60
    +  )
    
    61
    +import Data.Int
    
    62
    +  ( Int8, Int16, Int32, Int64 )
    
    63
    +import Data.IORef
    
    64
    +  ( newIORef, atomicModifyIORef' )
    
    65
    +import Data.Kind
    
    66
    +  ( Type )
    
    67
    +import Data.List
    
    68
    +  ( intercalate )
    
    69
    +import Data.Proxy
    
    70
    +  ( Proxy(..) )
    
    71
    +import Data.Word
    
    72
    +  ( Word8, Word16, Word32, Word64 )
    
    73
    +import GHC.TypeNats
    
    74
    +  ( Nat, KnownNat, natVal )
    
    75
    +import Numeric.Natural
    
    76
    +  ( Natural )
    
    77
    +import System.Environment
    
    78
    +  ( getArgs )
    
    79
    +import System.Exit
    
    80
    +  ( die, exitFailure )
    
    81
    +import Text.Read
    
    82
    +  ( readMaybe )
    
    83
    +
    
    84
    +-- transformers
    
    85
    +import Control.Monad.Trans.Reader
    
    86
    +  ( ReaderT, runReaderT, ask, local )
    
    87
    +import Control.Monad.Trans.State.Strict
    
    88
    +  ( State, state, runState )
    
    89
    +
    
    90
    +--------------------------------------------------------------------------------
    
    91
    +-- Core framework
    
    92
    +
    
    93
    +newtype Gen a = Gen { runGen :: State Word64 a }
    
    94
    +  deriving newtype ( Functor, Applicative, Monad )
    
    95
    +
    
    96
    +class Arbitrary a where
    
    97
    +  arbitrary :: Gen a
    
    98
    +
    
    99
    +class IsProperty p where
    
    100
    +  property :: p -> Property
    
    101
    +
    
    102
    +data PropertyCheck
    
    103
    +  = PropertyBinaryOp Bool String String String
    
    104
    +  | PropertyAnd PropertyCheck PropertyCheck
    
    105
    +
    
    106
    +instance IsProperty PropertyCheck where
    
    107
    +  property check = Prop (pure (PropertyEOA check))
    
    108
    +
    
    109
    +data PropertyTestArg
    
    110
    +  = PropertyEOA PropertyCheck
    
    111
    +  | PropertyArg String PropertyTestArg
    
    112
    +
    
    113
    +getCheck :: PropertyTestArg -> ([String], PropertyCheck)
    
    114
    +getCheck (PropertyEOA pc)    = ([], pc)
    
    115
    +getCheck (PropertyArg s pta) = let (ss, pc) = getCheck pta in (s:ss, pc)
    
    116
    +
    
    117
    +data Property = Prop { unProp :: Gen PropertyTestArg }
    
    118
    +
    
    119
    +instance (Show a, Arbitrary a, IsProperty prop) => IsProperty (a -> prop) where
    
    120
    +  property p = forAll arbitrary p
    
    121
    +
    
    122
    +-- | Run a generator for a value of the given type and add it as an argument
    
    123
    +-- to the property test.
    
    124
    +forAll :: (Show a, IsProperty prop) => Gen a -> (a -> prop) -> Property
    
    125
    +forAll generator tst = Prop $ do
    
    126
    +  a <- generator
    
    127
    +  augment a <$> unProp (property (tst a))
    
    128
    +  where
    
    129
    +    augment a arg = PropertyArg (show a) arg
    
    130
    +
    
    131
    +-- | Build a @PropertyCheck@ by comparing two values with a named predicate.
    
    132
    +propertyCompare :: Show a => String -> (a -> a -> Bool) -> a -> a -> PropertyCheck
    
    133
    +propertyCompare s f a b = PropertyBinaryOp (f a b) s (show a) (show b)
    
    134
    +
    
    135
    +-- | Check that two values are equal (by '==').
    
    136
    +(===) :: (Show a, Eq a) => a -> a -> PropertyCheck
    
    137
    +(===) = propertyCompare "==" (==)
    
    138
    +infix 4 ===
    
    139
    +
    
    140
    +-- | Conjunction of two property checks.
    
    141
    +propertyAnd :: PropertyCheck -> PropertyCheck -> PropertyCheck
    
    142
    +propertyAnd = PropertyAnd
    
    143
    +
    
    144
    +--------------------------------------------------------------------------------
    
    145
    +-- Test tree
    
    146
    +
    
    147
    +-- | A named test or group of tests.
    
    148
    +data Test where
    
    149
    +  Group    :: String -> [Test] -> Test
    
    150
    +  Property :: IsProperty prop => String -> prop -> Test
    
    151
    +
    
    152
    +--------------------------------------------------------------------------------
    
    153
    +-- Test runner
    
    154
    +
    
    155
    +newtype Iterations = Iterations { nbIterations :: Word }
    
    156
    +  deriving newtype ( Show, Eq, Ord )
    
    157
    +
    
    158
    +-- | Outcome of running a test suite.
    
    159
    +data Result = Success | Failure [[String]]
    
    160
    +
    
    161
    +instance Semigroup Result where
    
    162
    +  Success    <> y          = y
    
    163
    +  x          <> Success    = x
    
    164
    +  Failure xs <> Failure ys = Failure (xs ++ ys)
    
    165
    +
    
    166
    +instance Monoid Result where
    
    167
    +  mempty = Success
    
    168
    +
    
    169
    +data RunS = RunS
    
    170
    +  { depth       :: Int
    
    171
    +  , currentSeed :: Word64
    
    172
    +  , context     :: [String]
    
    173
    +  }
    
    174
    +
    
    175
    +putMsg :: String -> ReaderT RunS IO ()
    
    176
    +putMsg s = do
    
    177
    +  n <- depth <$> ask
    
    178
    +  liftIO . putStrLn $ replicate (n * 2) ' ' ++ s
    
    179
    +
    
    180
    +nest :: String -> ReaderT RunS IO a -> ReaderT RunS IO a
    
    181
    +nest c = local (\s -> s { depth = depth s + 1, context = c : context s })
    
    182
    +
    
    183
    +runPropertyCheck :: PropertyCheck -> ReaderT RunS IO Result
    
    184
    +runPropertyCheck (PropertyBinaryOp ok desc s1 s2) =
    
    185
    +  if ok
    
    186
    +    then return Success
    
    187
    +    else do
    
    188
    +      ctx <- context <$> ask
    
    189
    +      let msg = "Failure: " ++ s1 ++ " " ++ desc ++ " " ++ s2
    
    190
    +      putMsg msg
    
    191
    +      return (Failure [msg : ctx])
    
    192
    +runPropertyCheck (PropertyAnd a b) =
    
    193
    +  (<>) <$> runPropertyCheck a <*> runPropertyCheck b
    
    194
    +
    
    195
    +runProperty :: Iterations -> Property -> ReaderT RunS IO Result
    
    196
    +runProperty (Iterations iters) (Prop p) = do
    
    197
    +  startingSeed <- currentSeed <$> ask
    
    198
    +  loop iters startingSeed
    
    199
    +  where
    
    200
    +    loop 0 _ = do
    
    201
    +      putMsg ("Passed " ++ show iters ++ " iterations")
    
    202
    +      return Success
    
    203
    +    loop n s = do
    
    204
    +      let (pt, s') = runState (runGen p) s
    
    205
    +          (ss, pc) = getCheck pt
    
    206
    +      res <- runPropertyCheck pc
    
    207
    +      case res of
    
    208
    +        Success      -> loop (n - 1) s'
    
    209
    +        Failure msgs -> do
    
    210
    +          let msg = "With arguments " ++ intercalate ", " ss ++ " (Seed: " ++ show s ++ ")"
    
    211
    +          putMsg msg
    
    212
    +          return (Failure (map (msg :) msgs))
    
    213
    +
    
    214
    +-- | Run a single 'Test', accumulating all failures.
    
    215
    +runTestInternal :: Iterations -> Test -> ReaderT RunS IO Result
    
    216
    +runTestInternal iters (Group name tests) = do
    
    217
    +  let label = "Group " ++ name
    
    218
    +  putMsg label
    
    219
    +  env <- ask
    
    220
    +  nest label $ do
    
    221
    +    -- Compute initial seed for each test in the group, based on the
    
    222
    +    -- index of the test in the group.
    
    223
    +    let runOne idx t = do
    
    224
    +          let !s = snd $ stepLCG (currentSeed env + fromIntegral idx)
    
    225
    +          local (\e -> e { currentSeed = s }) (runTestInternal iters t)
    
    226
    +    mconcat <$> traverse (uncurry runOne) (zip [1..] tests)
    
    227
    +
    
    228
    +runTestInternal iters (Property name p) = do
    
    229
    +  let label = "Running " ++ name
    
    230
    +  putMsg label
    
    231
    +  nest label (runProperty iters (property p))
    
    232
    +
    
    233
    +showStack :: Int -> [String] -> String
    
    234
    +showStack _  []     = ""
    
    235
    +showStack n (s:ss) = replicate n ' ' ++ s ++ "\n" ++ showStack (n + 2) ss
    
    236
    +
    
    237
    +-- | Standard @main@ entry point for tests using 'MiniQuickCheck'.
    
    238
    +--
    
    239
    +-- Reads a 'Word64' seed from the first command-line argument, then
    
    240
    +-- delegates to 'runTests'.
    
    241
    +runTestsMain :: Iterations -> Test -> IO ()
    
    242
    +runTestsMain iters t = do
    
    243
    +  args <- getArgs
    
    244
    +  seed <- case args of
    
    245
    +    [arg] -> case readMaybe arg of
    
    246
    +      Just s  -> pure s
    
    247
    +      Nothing -> die $ "Invalid seed: " ++ show arg
    
    248
    +    _ -> die "Usage: <test-name> <seed>"
    
    249
    +  runTests iters seed t
    
    250
    +
    
    251
    +runTests :: Iterations -> Word64 -> Test -> IO ()
    
    252
    +runTests iters seed t = do
    
    253
    +  res <- runReaderT (runTestInternal iters t) (RunS 0 seed [])
    
    254
    +  case res of
    
    255
    +    Success      -> return ()
    
    256
    +    Failure tests -> do
    
    257
    +      putStrLn $ "Seed: " ++ show seed
    
    258
    +      putStrLn $ "These tests failed:\n"
    
    259
    +              ++ intercalate "\n" (map (showStack 0 . reverse) tests)
    
    260
    +      exitFailure
    
    261
    +
    
    262
    +--------------------------------------------------------------------------------
    
    263
    +-- Random number generation (linear congruences)
    
    264
    +
    
    265
    +-- Constants from Knuth's MMIX
    
    266
    +
    
    267
    +lcgMultiplier :: Word64
    
    268
    +lcgMultiplier = 6364136223846793005
    
    269
    +lcgIncrement :: Word64
    
    270
    +lcgIncrement = 1442695040888963407
    
    271
    +
    
    272
    +-- | Pure step function for the linear congruential generator
    
    273
    +stepLCG :: Word64 -> (Word64, Word64)
    
    274
    +stepLCG s =
    
    275
    +  let s' = s * lcgMultiplier + lcgIncrement
    
    276
    +  in (s', s')
    
    277
    +
    
    278
    +--------------------------------------------------------------------------------
    
    279
    +-- Primitive generators
    
    280
    +
    
    281
    +-- | Generate a uniformly random 'Word64'.
    
    282
    +arbitraryWord64 :: Gen Word64
    
    283
    +arbitraryWord64 = Gen $ state stepLCG
    
    284
    +
    
    285
    +-- | Generate a uniformly random 'Int64' (bit-reinterpretation of a Word64).
    
    286
    +arbitraryInt64 :: Gen Int64
    
    287
    +arbitraryInt64 = fromIntegral <$> arbitraryWord64
    
    288
    +
    
    289
    +-- | Shrink a random 'Int64' down to a smaller integral type.
    
    290
    +integralDownsize :: (Integral a, FiniteBits a) => Int64 -> a
    
    291
    +integralDownsize = wordDownsize . fromIntegral
    
    292
    +
    
    293
    +-- | Shrink a random 'Word64' down to a smaller integral type.
    
    294
    +wordDownsize :: forall a. (Integral a, FiniteBits a) => Word64 -> a
    
    295
    +wordDownsize w =
    
    296
    +  fromIntegral (w `shiftR` (64 - finiteBitSize (undefined :: a)))
    
    297
    +    -- take the higher bits (more random with our LCG)
    
    298
    +
    
    299
    +--------------------------------------------------------------------------------
    
    300
    +-- Basic Arbitrary instances
    
    301
    +
    
    302
    +instance Arbitrary Bool where
    
    303
    +  arbitrary = ( == 1 ) . ( `shiftR` 63 ) <$> arbitraryWord64
    
    304
    +
    
    305
    +instance Arbitrary Word64 where
    
    306
    +  arbitrary = arbitraryWord64
    
    307
    +instance Arbitrary Word32 where
    
    308
    +  arbitrary = wordDownsize <$> arbitraryWord64
    
    309
    +instance Arbitrary Word16 where
    
    310
    +  arbitrary = wordDownsize <$> arbitraryWord64
    
    311
    +instance Arbitrary Word8 where
    
    312
    +  arbitrary = wordDownsize <$> arbitraryWord64
    
    313
    +instance Arbitrary Word where
    
    314
    +  arbitrary = fromIntegral <$> arbitraryWord64
    
    315
    +
    
    316
    +instance Arbitrary Int64 where
    
    317
    +  arbitrary = arbitraryInt64
    
    318
    +instance Arbitrary Int32 where
    
    319
    +  arbitrary = integralDownsize <$> arbitraryInt64
    
    320
    +instance Arbitrary Int16 where
    
    321
    +  arbitrary = integralDownsize <$> arbitraryInt64
    
    322
    +instance Arbitrary Int8 where
    
    323
    +  arbitrary = integralDownsize <$> arbitraryInt64
    
    324
    +instance Arbitrary Int where
    
    325
    +  arbitrary = fromIntegral <$> arbitraryInt64
    
    326
    +
    
    327
    +-- | Generates a natural number with at most 192 bits set.
    
    328
    +instance Arbitrary Natural where
    
    329
    +  arbitrary = do
    
    330
    +    cx <- ( `shiftR` 62 ) <$> arbitraryWord64
    
    331
    +    n1 <- fromIntegral <$> arbitraryWord64
    
    332
    +    n2 <- fromIntegral <$> arbitraryWord64
    
    333
    +    n3 <- fromIntegral <$> arbitraryWord64
    
    334
    +
    
    335
    +    pure $ case cx of
    
    336
    +      0 -> n1
    
    337
    +      1 -> (n1 `shiftL` 64) .|. n2
    
    338
    +      _ -> (n1 `shiftL` 128) .|. (n2 `shiftL` 64) .|. n3
    
    339
    +
    
    340
    +-- | Generates an integer with at most 192 bits set.
    
    341
    +instance Arbitrary Integer where
    
    342
    +  arbitrary = do
    
    343
    +    nat <- arbitrary @Natural
    
    344
    +    neg <- arbitrary @Bool
    
    345
    +
    
    346
    +    pure $
    
    347
    +      if neg
    
    348
    +      then negate (fromIntegral nat)
    
    349
    +      else fromIntegral nat
    
    350
    +
    
    351
    +instance Arbitrary Char where
    
    352
    +  arbitrary = do
    
    353
    +    let high = fromIntegral (fromEnum (maxBound :: Char)) :: Word
    
    354
    +    x <- arbitrary
    
    355
    +    return (toEnum . fromIntegral $ x `mod` (high + 1))
    
    356
    +
    
    357
    +--------------------------------------------------------------------------------
    
    358
    +-- Useful newtypes for different Arbitrary instances
    
    359
    +
    
    360
    +-- | Wrapper for non-zero values.
    
    361
    +newtype NonZero a = NonZero { getNonZero :: a }
    
    362
    +  deriving (Eq, Ord, Bounded, Show)
    
    363
    +
    
    364
    +-- | Generator that rejects zero values.
    
    365
    +nonZero :: (Arbitrary a, Num a, Eq a) => Gen (NonZero a)
    
    366
    +nonZero = do
    
    367
    +  x <- arbitrary
    
    368
    +  if x == 0 then nonZero else pure (NonZero x)
    
    369
    +
    
    370
    +instance (Arbitrary a, Num a, Eq a) => Arbitrary (NonZero a) where
    
    371
    +  arbitrary = nonZero
    
    372
    +
    
    373
    +-- | Shift amount bounded to @[0, finiteBitSize - 1]@.
    
    374
    +newtype BoundedShiftAmount a = BoundedShiftAmount { getBoundedShiftAmount :: Int }
    
    375
    +  deriving (Eq, Ord, Show)
    
    376
    +
    
    377
    +instance FiniteBits a => Arbitrary (BoundedShiftAmount a) where
    
    378
    +  arbitrary = do
    
    379
    +    x <- arbitrary
    
    380
    +    let w = finiteBitSize (undefined :: a)
    
    381
    +    pure $ BoundedShiftAmount (abs x `mod` w)
    
    382
    +
    
    383
    +-- | @a `BoundedBy` n@ represents numbers with maximum absolute value @n@ (inclusive).
    
    384
    +type BoundedBy :: Type -> Nat -> Type
    
    385
    +newtype BoundedBy a n = BoundedBy { getBoundedBy :: a }
    
    386
    +  deriving (Eq, Ord, Show)
    
    387
    +
    
    388
    +instance
    
    389
    +  forall n a
    
    390
    +  .  ( KnownNat n, Integral a, Arbitrary a )
    
    391
    +  => Arbitrary ( a `BoundedBy` n ) where
    
    392
    +  arbitrary = BoundedBy . (`rem` (n + 1)) <$> arbitrary
    
    393
    +    where
    
    394
    +      n :: a
    
    395
    +      n = fromIntegral $ natVal @n Proxy

  • testsuite/tests/numeric/should_run/all.T
    ... ... @@ -3,8 +3,6 @@
    3 3
     #	extra run flags
    
    4 4
     #	expected process return value, if not zero
    
    5 5
     
    
    6
    -import random
    
    7
    -
    
    8 6
     # some bugs only surface with -O, omitting optasm may cause them to
    
    9 7
     # slip into releases! (e.g. #26711)
    
    10 8
     setTestOpts(when(have_ncg(), extra_ways(['optasm'])))
    
    ... ... @@ -89,7 +87,14 @@ test('T20291', normal, compile_and_run, [''])
    89 87
     test('T22282', normal, compile_and_run, [''])
    
    90 88
     test('T22671', js_fragile(24259), compile_and_run, [''])
    
    91 89
     # the high run timeout multiplier exists because of timeouts with the wasm backend
    
    92
    -test('foundation', [run_timeout_multiplier(4), js_fragile(24259), extra_ways(['optasm','ghci','ghci-opt']), extra_run_opts(str(random.getrandbits(64)))], compile_and_run, ['-fno-break-points'])
    
    90
    +test('foundation',
    
    91
    +     [ mini_quickcheck
    
    92
    +     , run_timeout_multiplier(4)
    
    93
    +     , js_fragile(24259)
    
    94
    +     , extra_ways(['optasm','ghci','ghci-opt'])
    
    95
    +     ]
    
    96
    +     , multimod_compile_and_run
    
    97
    +     , ['foundation', '-fno-break-points'])
    
    93 98
     test('T24066', normal, compile_and_run, [''])
    
    94 99
     test('div01', normal, compile_and_run, [''])
    
    95 100
     test('T24245', normal, compile_and_run, [''])
    

  • testsuite/tests/numeric/should_run/foundation.hs
    ... ... @@ -23,252 +23,20 @@ module Main
    23 23
         ( main
    
    24 24
         ) where
    
    25 25
     
    
    26
    -import Data.Array.Byte
    
    27
    -import Data.Bits (Bits((.&.), bit), FiniteBits, finiteBitSize)
    
    28
    -import Data.Word
    
    26
    +import Data.Bits       (Bits((.&.), bit))
    
    27
    +import Data.Function   (on)
    
    29 28
     import Data.Int
    
    30
    -import GHC.Natural
    
    31 29
     import Data.Typeable
    
    30
    +import Data.Word
    
    32 31
     import GHC.Int
    
    33
    -import GHC.Word
    
    34
    -import Data.Function
    
    32
    +import GHC.Natural
    
    35 33
     import GHC.Prim
    
    36
    -import Control.Monad.Reader
    
    37
    -import Data.List (intercalate)
    
    38
    -import System.Environment (getArgs)
    
    39
    -import Text.Read (readMaybe)
    
    40
    -import Unsafe.Coerce
    
    41 34
     import GHC.Types
    
    42
    -import Data.Char
    
    43
    -import System.Exit
    
    44
    -
    
    35
    +import GHC.Word
    
    45 36
     import qualified GHC.Internal.PrimopWrappers as Wrapper
    
    46
    -import qualified GHC.Internal.Prim as Primop
    
    47
    -
    
    48
    -newtype Gen a = Gen { runGen :: (ReaderT LCGGen IO a) }
    
    49
    -  deriving newtype (Functor, Applicative, Monad)
    
    50
    -
    
    51
    -class Arbitrary a where
    
    52
    -  arbitrary :: Gen a
    
    53
    -
    
    54
    -class IsProperty p where
    
    55
    -    property :: p -> Property
    
    37
    +import qualified GHC.Internal.Prim           as Primop
    
    56 38
     
    
    57
    -data PropertyCheck = PropertyBinaryOp Bool String String String
    
    58
    -                   | PropertyAnd PropertyCheck PropertyCheck
    
    59
    -
    
    60
    -instance IsProperty PropertyCheck where
    
    61
    -    property check = Prop $ pure (PropertyEOA check)
    
    62
    -
    
    63
    -data PropertyTestArg = PropertyEOA PropertyCheck
    
    64
    -                     | PropertyArg String PropertyTestArg
    
    65
    -
    
    66
    -getCheck :: PropertyTestArg -> ([String], PropertyCheck)
    
    67
    -getCheck (PropertyEOA pc) = ([], pc)
    
    68
    -getCheck (PropertyArg s pta ) = let (ss, pc) = getCheck pta in (s:ss, pc)
    
    69
    -
    
    70
    -data Property = Prop { unProp :: Gen PropertyTestArg }
    
    71
    -
    
    72
    -instance (Show a, Arbitrary a, IsProperty prop) => IsProperty (a -> prop) where
    
    73
    -    property p = forAll arbitrary p
    
    74
    -
    
    75
    --- | Running a generator for a specific type under a property
    
    76
    -forAll :: (Show a, IsProperty prop) => Gen a -> (a -> prop) -> Property
    
    77
    -forAll generator tst = Prop $ do
    
    78
    -    a <- generator
    
    79
    -    augment a <$> unProp (property (tst a))
    
    80
    -  where
    
    81
    -    augment a arg = PropertyArg (show a) arg
    
    82
    -
    
    83
    --- | A property that check for equality of its 2 members.
    
    84
    -propertyCompare :: (Show a) => String -> (a -> a -> Bool) -> a -> a -> PropertyCheck
    
    85
    -propertyCompare s f a b =
    
    86
    -    let sa = show a
    
    87
    -        sb = show b
    
    88
    -     in PropertyBinaryOp (a `f` b) s sa sb
    
    89
    -
    
    90
    -(===) :: (Show a, Eq a) => a -> a -> PropertyCheck
    
    91
    -(===) = propertyCompare "==" (==)
    
    92
    -infix 4 ===
    
    93
    -
    
    94
    -propertyAnd = PropertyAnd
    
    95
    -
    
    96
    -
    
    97
    -data Test where
    
    98
    -  Group :: String -> [Test] -> Test
    
    99
    -  Property :: IsProperty prop => String -> prop -> Test
    
    100
    -
    
    101
    -
    
    102
    -arbitraryInt64 :: Gen Int64
    
    103
    -arbitraryInt64 = Gen $ do
    
    104
    -    h <- ask
    
    105
    -    W64# w <- liftIO (randomWord64 h)
    
    106
    -    return (I64# (unsafeCoerce# w))
    
    107
    -
    
    108
    -integralDownsize :: (Integral a) => Int64 -> a
    
    109
    -integralDownsize = fromIntegral
    
    110
    -
    
    111
    -wordDownsize :: (Integral a) => Word64 -> a
    
    112
    -wordDownsize = fromIntegral
    
    113
    -
    
    114
    -arbitraryWord64 :: Gen Word64
    
    115
    -arbitraryWord64 = Gen $ do
    
    116
    -    h <- ask
    
    117
    -    liftIO (randomWord64 h)
    
    118
    -
    
    119
    -nonZero :: (Arbitrary a, Num a, Eq a) => Gen (NonZero a)
    
    120
    -nonZero = do
    
    121
    -  x <- arbitrary
    
    122
    -  if x == 0 then nonZero else pure $ NonZero x
    
    123
    -
    
    124
    -newtype NonZero a = NonZero { getNonZero :: a }
    
    125
    -  deriving (Eq,Ord,Bounded,Show)
    
    126
    -
    
    127
    -instance (Arbitrary a, Num a, Eq a) => Arbitrary (NonZero a) where
    
    128
    -  arbitrary = nonZero
    
    129
    -
    
    130
    --- | A newtype for shift amounts that are bounded by @wordSize - 1@
    
    131
    -newtype BoundedShiftAmount a = BoundedShiftAmount {getBoundedShiftAmount :: Int}
    
    132
    -  deriving (Eq, Ord, Show)
    
    133
    -
    
    134
    -instance (FiniteBits a) => Arbitrary (BoundedShiftAmount a) where
    
    135
    -  arbitrary = do
    
    136
    -    x <- arbitrary
    
    137
    -    let widthBits = finiteBitSize (undefined :: a)
    
    138
    -    pure $ BoundedShiftAmount (abs x `mod` widthBits)
    
    139
    -
    
    140
    -instance Arbitrary Natural where
    
    141
    -    arbitrary = integralDownsize . (`mod` 10000) . abs <$> arbitraryInt64
    
    142
    -
    
    143
    --- Bounded by Int64
    
    144
    -instance Arbitrary Integer where
    
    145
    -    arbitrary = fromIntegral <$> arbitraryInt64
    
    146
    -
    
    147
    -instance Arbitrary Int where
    
    148
    -    arbitrary = int64ToInt <$> arbitraryInt64
    
    149
    -instance Arbitrary Word where
    
    150
    -    arbitrary = word64ToWord <$> arbitraryWord64
    
    151
    -instance Arbitrary Word64 where
    
    152
    -    arbitrary = arbitraryWord64
    
    153
    -instance Arbitrary Word32 where
    
    154
    -    arbitrary = wordDownsize <$> arbitraryWord64
    
    155
    -instance Arbitrary Word16 where
    
    156
    -    arbitrary = wordDownsize <$> arbitraryWord64
    
    157
    -instance Arbitrary Word8 where
    
    158
    -    arbitrary = wordDownsize <$> arbitraryWord64
    
    159
    -instance Arbitrary Int64 where
    
    160
    -    arbitrary = arbitraryInt64
    
    161
    -instance Arbitrary Int32 where
    
    162
    -    arbitrary = integralDownsize <$> arbitraryInt64
    
    163
    -instance Arbitrary Int16 where
    
    164
    -    arbitrary = integralDownsize <$> arbitraryInt64
    
    165
    -instance Arbitrary Int8 where
    
    166
    -    arbitrary = integralDownsize <$> arbitraryInt64
    
    167
    -
    
    168
    -instance Arbitrary Char where
    
    169
    -    arbitrary = do
    
    170
    -      let high = fromIntegral $ fromEnum (maxBound :: Char) :: Word
    
    171
    -      (x::Word) <- arbitrary
    
    172
    -      let x' = mod x high
    
    173
    -      return (chr $ fromIntegral x')
    
    174
    -
    
    175
    -int64ToInt :: Int64 -> Int
    
    176
    -int64ToInt (I64# i) = I# (int64ToInt# i)
    
    177
    -
    
    178
    -
    
    179
    -word64ToWord :: Word64 -> Word
    
    180
    -word64ToWord (W64# i) = W# (word64ToWord# i)
    
    181
    -
    
    182
    -
    
    183
    -data RunS = RunS { depth :: Int, rg :: LCGGen, context :: [String] }
    
    184
    -
    
    185
    -newtype LCGGen = LCGGen { randomWord64 :: IO Word64 }
    
    186
    -
    
    187
    -data LCGParams = LCGParams { seed :: Word64, a :: Word64, c :: Word64, m :: Word64 }
    
    188
    -
    
    189
    -newLCGGen :: LCGParams -> IO LCGGen
    
    190
    -newLCGGen LCGParams {seed = W64# seed#, ..} = do
    
    191
    -  MutableByteArray mba# <- IO $ \s0 -> case newByteArray# 8# s0 of
    
    192
    -    (# s1, mba# #) -> case writeWord64Array# mba# 0# seed# s1 of
    
    193
    -      s2 -> (# s2, MutableByteArray mba# #)
    
    194
    -  pure $ LCGGen $ IO $ \s0 -> case readWord64Array# mba# 0# s0 of
    
    195
    -    (# s1, old_val# #) ->
    
    196
    -      let old_val = W64# old_val#
    
    197
    -          !new_val@(W64# new_val#) = (old_val * a + c) `mod` m
    
    198
    -       in case writeWord64Array# mba# 0# new_val# s1 of
    
    199
    -            s2 -> (# s2, new_val #)
    
    200
    -
    
    201
    -runPropertyCheck (PropertyBinaryOp res desc s1 s2) =
    
    202
    -  if res then return Success
    
    203
    -         else do
    
    204
    -          ctx <- context <$> ask
    
    205
    -          let msg = "Failure: " ++ s1 ++ desc ++ s2
    
    206
    -          putMsg msg
    
    207
    -          return (Failure [msg : ctx])
    
    208
    -runPropertyCheck (PropertyAnd a1 a2) = (<>) <$> runPropertyCheck a1 <*> runPropertyCheck a2
    
    209
    -
    
    210
    -runProperty :: Property -> ReaderT RunS IO Result
    
    211
    -runProperty (Prop p) = do
    
    212
    -  let iterations = 1000 :: Int
    
    213
    -  loop iterations iterations
    
    214
    -  where
    
    215
    -    loop iterations 0 = do
    
    216
    -      putMsg ("Passed " ++ show iterations ++ " iterations")
    
    217
    -      return Success
    
    218
    -    loop iterations n = do
    
    219
    -      h <- rg <$> ask
    
    220
    -      p <- liftIO (runReaderT (runGen p) h)
    
    221
    -      let (ss, pc) = getCheck p
    
    222
    -      res <- runPropertyCheck pc
    
    223
    -      case res of
    
    224
    -        Success -> loop iterations (n-1)
    
    225
    -        Failure msgs -> do
    
    226
    -          let msg = ("With arguments " ++ intercalate ", " ss)
    
    227
    -          putMsg msg
    
    228
    -          return (Failure (map (msg :) msgs))
    
    229
    -
    
    230
    -data Result = Success | Failure [[String]]
    
    231
    -
    
    232
    -instance Semigroup Result where
    
    233
    -  Success <> x = x
    
    234
    -  x <> Success = x
    
    235
    -  (Failure xs) <> (Failure ys) = Failure (xs ++ ys)
    
    236
    -
    
    237
    -instance Monoid Result where
    
    238
    -  mempty = Success
    
    239
    -
    
    240
    -putMsg s = do
    
    241
    -  n <- depth <$> ask
    
    242
    -  liftIO . putStrLn $ replicate (n * 2) ' ' ++ s
    
    243
    -
    
    244
    -
    
    245
    -nest c = local (\s -> s { depth = depth s + 1, context = c : context s })
    
    246
    -
    
    247
    -runTestInternal :: Test -> ReaderT RunS IO Result
    
    248
    -runTestInternal (Group name tests) = do
    
    249
    -  let label = ("Group " ++ name)
    
    250
    -  putMsg label
    
    251
    -  nest label (mconcat <$> mapM runTestInternal tests)
    
    252
    -runTestInternal (Property name p) = do
    
    253
    -  let label = ("Running " ++ name)
    
    254
    -  putMsg label
    
    255
    -  nest label $ runProperty (property p)
    
    256
    -
    
    257
    -
    
    258
    -runTests :: Word64 -> Test -> IO ()
    
    259
    -runTests seed t = do
    
    260
    -  -- These params are the same ones as glibc uses.
    
    261
    -  h <- newLCGGen (LCGParams { seed, m = 2 ^ (31 :: Int), a = 1103515245, c = 12345 })
    
    262
    -  res <- runReaderT  (runTestInternal t) (RunS 0 h [])
    
    263
    -  case res of
    
    264
    -    Success -> return ()
    
    265
    -    Failure tests -> do
    
    266
    -      putStrLn $ "Seed: " ++ show seed
    
    267
    -      putStrLn $ "These tests failed:  \n" ++ intercalate "  \n" (map (showStack 0 . reverse) tests)
    
    268
    -      exitFailure
    
    269
    -
    
    270
    -showStack _ [] = ""
    
    271
    -showStack n (s:ss) = replicate n ' ' ++ s ++ "\n" ++ showStack (n + 2) ss
    
    39
    +import MiniQuickCheck
    
    272 40
     
    
    273 41
     -------------------------------------------------------------------------------
    
    274 42
     
    
    ... ... @@ -325,8 +93,11 @@ testOperatorPrecedence _ = Group "Precedence"
    325 93
         , Property "+ and * (2)" $ \(a :: a) (b :: a) (c :: a) -> (a * b + c) === ((a * b) + c)
    
    326 94
         , Property "- and * (1)" $ \(a :: a) (b :: a) (c :: a) -> (a - b * c) === (a - (b * c))
    
    327 95
         , Property "- and * (2)" $ \(a :: a) (b :: a) (c :: a) -> (a * b - c) === ((a * b) - c)
    
    328
    -    , Property "* and ^ (1)" $ \(a :: a) (b :: Natural) (c :: a) -> (a ^ b * c) === ((a ^ b) * c)
    
    329
    -    , Property "* and ^ (2)" $ \(a :: a) (c :: Natural) (b :: a) -> (a * b ^ c) === (a * (b ^ c))
    
    96
    +
    
    97
    +      -- Bound the exponent to avoid OOM errors e.g.
    
    98
    +      --   GNU MP: Cannot allocate memory (size=4294938656)
    
    99
    +    , Property "* and ^ (1)" $ \(a :: a) (BoundedBy b :: Natural `BoundedBy` 100) (c :: a) -> (a ^ b * c) === ((a ^ b) * c)
    
    100
    +    , Property "* and ^ (2)" $ \(a :: a) (BoundedBy c :: Natural `BoundedBy` 100) (b :: a) -> (a * b ^ c) === (a * (b ^ c))
    
    330 101
         ]
    
    331 102
     
    
    332 103
     
    
    ... ... @@ -454,19 +225,8 @@ instance TestPrimop LowerBitsAreDefined where
    454 225
     twoNonZero :: (a -> a -> b) -> a -> NonZero a -> b
    
    455 226
     twoNonZero f x (NonZero y) = f x y
    
    456 227
     
    
    457
    -getSeedFromArgs :: IO Word64
    
    458
    -getSeedFromArgs = do
    
    459
    -  args <- getArgs
    
    460
    -  case args of
    
    461
    -    [arg] -> case readMaybe arg of
    
    462
    -      Just seed -> pure seed
    
    463
    -      Nothing -> die $ "Invalid seed (expected Word64): " ++ show arg
    
    464
    -    _ -> die "Usage: foundation <seed>"
    
    465
    -
    
    466 228
     main :: IO ()
    
    467
    -main = do
    
    468
    -  seed <- getSeedFromArgs
    
    469
    -  runTests seed (Group "ALL" [testNumberRefs, testPrimops])
    
    229
    +main = runTestsMain (Iterations 1000) (Group "ALL" [testNumberRefs, testPrimops])
    
    470 230
     
    
    471 231
     -- Test an interpreted primop vs a compiled primop
    
    472 232
     testPrimops = Group "primop"
    

  • testsuite/tests/simd/should_run/all.T
    ... ... @@ -80,7 +80,7 @@ test('simd002', [], compile_and_run, [''])
    80 80
     test('simd003', [], compile_and_run, [''])
    
    81 81
     test('simd004', [], compile_and_run, ['-O2'])
    
    82 82
     test('simd005', [], compile_and_run, [''])
    
    83
    -test('simd006', [], compile_and_run, [''])
    
    83
    +test('simd006', [mini_quickcheck], multimod_compile_and_run, ['simd006', ''])
    
    84 84
     test('simd007', [], compile_and_run, [''])
    
    85 85
     test('simd008', [], compile_and_run, [''])
    
    86 86
     test('simd009', [ req_th
    

  • testsuite/tests/simd/should_run/simd006.hs
    1
    -{-# LANGUAGE MagicHash #-}
    
    2
    -{-# LANGUAGE UnboxedTuples #-}
    
    3
    -{-# LANGUAGE FlexibleContexts    #-}
    
    4
    -{-# LANGUAGE OverloadedStrings   #-}
    
    5
    -{-# LANGUAGE ScopedTypeVariables #-}
    
    6
    -{-# LANGUAGE TypeFamilies        #-}
    
    7
    -{-# LANGUAGE DerivingStrategies #-}
    
    1
    +{-# LANGUAGE MagicHash           #-}
    
    2
    +{-# LANGUAGE UnboxedTuples       #-}
    
    3
    +{-# LANGUAGE DerivingStrategies  #-}
    
    8 4
     {-# LANGUAGE GeneralisedNewtypeDeriving #-}
    
    9
    -{-# LANGUAGE MagicHash #-}
    
    10
    -{-# LANGUAGE RecordWildCards #-}
    
    5
    +{-# LANGUAGE ScopedTypeVariables #-}
    
    11 6
     
    
    12
    --- QuickCheck testing for SIMD operations
    
    7
    +-- QuickCheck-like property tests for SIMD vector operations.
    
    13 8
     
    
    14
    -module Main
    
    15
    -    ( main
    
    16
    -    ) where
    
    9
    +module Main (main) where
    
    17 10
     
    
    18
    -import Data.Word
    
    19
    -import Data.Int
    
    20
    -import GHC.Natural
    
    21 11
     import Data.Coerce
    
    22
    -import Data.Typeable
    
    23
    -import Data.Proxy
    
    24
    -import GHC.Int
    
    25
    -import GHC.Word
    
    26
    -import Data.Function
    
    12
    +import Data.Word
    
    27 13
     import GHC.Prim
    
    28
    -import Control.Monad.Reader
    
    29
    -import System.IO
    
    30
    -import Foreign.Marshal.Alloc
    
    31
    -import Foreign.Storable
    
    32
    -import Foreign.Ptr
    
    33
    -import Data.List (intercalate)
    
    34
    -import Data.IORef
    
    35
    -import Unsafe.Coerce
    
    36 14
     import GHC.Exts
    
    37 15
     import GHC.Float
    
    38 16
       ( castFloatToWord32 , castWord32ToFloat
    
    39 17
       , castDoubleToWord64, castWord64ToDouble
    
    40 18
       )
    
    41 19
     
    
    20
    +import MiniQuickCheck
    
    42 21
     
    
    22
    +--------------------------------------------------------------------------------
    
    23
    +-- Scalar wrappers that use bit-equality to test for equality.
    
    43 24
     
    
    44
    -newtype Gen a = Gen { runGen :: (ReaderT LCGGen IO a) }
    
    45
    -  deriving newtype (Functor, Applicative, Monad)
    
    46
    -
    
    47
    -class Arbitrary a where
    
    48
    -  arbitrary :: Gen a
    
    49
    -
    
    50
    -class IsProperty p where
    
    51
    -    property :: p -> Property
    
    52
    -
    
    53
    -data PropertyCheck = PropertyBinaryOp Bool String String String
    
    54
    -                   | PropertyAnd PropertyCheck PropertyCheck
    
    55
    -
    
    56
    -instance IsProperty PropertyCheck where
    
    57
    -    property check = Prop $ pure (PropertyEOA check)
    
    58
    -
    
    59
    -data PropertyTestArg = PropertyEOA PropertyCheck
    
    60
    -                     | PropertyArg String PropertyTestArg
    
    61
    -
    
    62
    -getCheck :: PropertyTestArg -> ([String], PropertyCheck)
    
    63
    -getCheck (PropertyEOA pc) = ([], pc)
    
    64
    -getCheck (PropertyArg s pta ) = let (ss, pc) = getCheck pta in (s:ss, pc)
    
    65
    -
    
    66
    -data Property = Prop { unProp :: Gen PropertyTestArg }
    
    67
    -
    
    68
    -instance (Show a, Arbitrary a, IsProperty prop) => IsProperty (a -> prop) where
    
    69
    -    property p = forAll arbitrary p
    
    70
    -
    
    71
    --- | Running a generator for a specific type under a property
    
    72
    -forAll :: (Show a, IsProperty prop) => Gen a -> (a -> prop) -> Property
    
    73
    -forAll generator tst = Prop $ do
    
    74
    -    a <- generator
    
    75
    -    augment a <$> unProp (property (tst a))
    
    76
    -  where
    
    77
    -    augment a arg = PropertyArg (show a) arg
    
    78
    -
    
    79
    --- | A property that check for equality of its 2 members.
    
    80
    -propertyCompare :: (Show a) => String -> (a -> a -> Bool) -> a -> a -> PropertyCheck
    
    81
    -propertyCompare s f a b =
    
    82
    -    let sa = show a
    
    83
    -        sb = show b
    
    84
    -     in PropertyBinaryOp (a `f` b) s sa sb
    
    85
    -
    
    86
    -(===) :: (Show a, Eq a) => a -> a -> PropertyCheck
    
    87
    -(===) = propertyCompare "==" (==)
    
    88
    -infix 4 ===
    
    89
    -
    
    90
    -propertyAnd = PropertyAnd
    
    91
    -
    
    92
    -
    
    93
    -data Test where
    
    94
    -  Group :: String -> [Test] -> Test
    
    95
    -  Property :: IsProperty prop => String -> prop -> Test
    
    96
    -
    
    25
    +newtype FloatNT = FloatNT Float
    
    26
    +  deriving newtype (Show, Num)
    
    97 27
     
    
    98
    -arbitraryInt64 :: Gen Int64
    
    99
    -arbitraryInt64 = Gen $ do
    
    100
    -    h <- ask
    
    101
    -    W64# w <- liftIO (randomWord64 h)
    
    102
    -    return (I64# (unsafeCoerce# w))
    
    28
    +instance Eq FloatNT where
    
    29
    +  FloatNT f1 == FloatNT f2 = castFloatToWord32 f1 == castFloatToWord32 f2
    
    103 30
     
    
    104
    -integralDownsize :: (Integral a) => Int64 -> a
    
    105
    -integralDownsize = fromIntegral
    
    31
    +instance Arbitrary FloatNT where
    
    32
    +  arbitrary = FloatNT . castWord32ToFloat <$> arbitrary
    
    106 33
     
    
    107
    -wordDownsize :: (Integral a) => Word64 -> a
    
    108
    -wordDownsize = fromIntegral
    
    34
    +newtype DoubleNT = DoubleNT Double
    
    35
    +  deriving newtype (Show, Num)
    
    109 36
     
    
    110
    -arbitraryWord64 :: Gen Word64
    
    111
    -arbitraryWord64 = Gen $ do
    
    112
    -    h <- ask
    
    113
    -    liftIO (randomWord64 h)
    
    37
    +instance Eq DoubleNT where
    
    38
    +  DoubleNT d1 == DoubleNT d2 = castDoubleToWord64 d1 == castDoubleToWord64 d2
    
    114 39
     
    
    40
    +instance Arbitrary DoubleNT where
    
    41
    +  arbitrary = DoubleNT . castWord64ToDouble <$> arbitrary
    
    115 42
     
    
    116
    -instance Arbitrary Word64 where
    
    117
    -    arbitrary = arbitraryWord64
    
    118
    -instance Arbitrary Word32 where
    
    119
    -    arbitrary = wordDownsize <$> arbitraryWord64
    
    43
    +--------------------------------------------------------------------------------
    
    44
    +-- Min/max for the types under test
    
    120 45
     
    
    121 46
     class HasMinMax a where
    
    122 47
       mini, maxi :: a -> a -> a
    
    48
    +
    
    123 49
     instance HasMinMax FloatNT where
    
    124 50
       mini (FloatNT (F# f1)) (FloatNT (F# f2)) = FloatNT (F# (minFloat# f1 f2))
    
    125 51
       maxi (FloatNT (F# f1)) (FloatNT (F# f2)) = FloatNT (F# (maxFloat# f1 f2))
    
    52
    +
    
    126 53
     instance HasMinMax DoubleNT where
    
    127 54
       mini (DoubleNT (D# d1)) (DoubleNT (D# d2)) = DoubleNT (D# (minDouble# d1 d2))
    
    128 55
       maxi (DoubleNT (D# d1)) (DoubleNT (D# d2)) = DoubleNT (D# (maxDouble# d1 d2))
    
    129 56
     
    
    130
    -newtype FloatNT = FloatNT Float
    
    131
    -  deriving newtype (Show, Num)
    
    132
    -instance Eq FloatNT where
    
    133
    -  FloatNT f1 == FloatNT f2 =
    
    134
    -    castFloatToWord32 f1 == castFloatToWord32 f2
    
    135
    -instance Arbitrary FloatNT where
    
    136
    -  arbitrary = FloatNT . castWord32ToFloat <$> arbitrary
    
    137
    -newtype DoubleNT = DoubleNT Double
    
    138
    -  deriving newtype (Show, Num)
    
    139
    -instance Eq DoubleNT where
    
    140
    -  DoubleNT d1 == DoubleNT d2 =
    
    141
    -    castDoubleToWord64 d1 == castDoubleToWord64 d2
    
    142
    -instance Arbitrary DoubleNT where
    
    143
    -  arbitrary = DoubleNT . castWord64ToDouble <$> arbitrary
    
    144
    -
    
    57
    +--------------------------------------------------------------------------------
    
    58
    +-- SIMD vector types
    
    145 59
     
    
    146 60
     data FloatX4 = FX4# FloatX4#
    
    61
    +
    
    147 62
     instance Show FloatX4 where
    
    148
    -  show (FX4# f) = case (unpackFloatX4# f) of
    
    149
    -    (# a, b, c, d #) -> show ((F# a), (F# b), (F# c), (F# d))
    
    63
    +  show (FX4# f) = case unpackFloatX4# f of
    
    64
    +    (# a, b, c, d #) -> show (F# a, F# b, F# c, F# d)
    
    65
    +
    
    150 66
     instance Eq FloatX4 where
    
    151
    -  (FX4# a) == (FX4# b)
    
    152
    -    = case (unpackFloatX4# a) of
    
    67
    +  FX4# a == FX4# b
    
    68
    +    = case unpackFloatX4# a of
    
    153 69
             (# a1, a2, a3, a4 #) ->
    
    154
    -          case (unpackFloatX4# b) of
    
    155
    -            (# b1, b2, b3, b4 #) -> FloatNT (F# a1) == FloatNT (F# b1) &&
    
    156
    -                                    FloatNT (F# a2) == FloatNT (F# b2) &&
    
    157
    -                                    FloatNT (F# a3) == FloatNT (F# b3) &&
    
    158
    -                                    FloatNT (F# a4) == FloatNT (F# b4)
    
    70
    +          case unpackFloatX4# b of
    
    71
    +            (# b1, b2, b3, b4 #) ->
    
    72
    +              FloatNT (F# a1) == FloatNT (F# b1) &&
    
    73
    +              FloatNT (F# a2) == FloatNT (F# b2) &&
    
    74
    +              FloatNT (F# a3) == FloatNT (F# b3) &&
    
    75
    +              FloatNT (F# a4) == FloatNT (F# b4)
    
    76
    +
    
    159 77
     instance Arbitrary FloatX4 where
    
    160 78
       arbitrary = do
    
    161 79
         FloatNT (F# f1) <- arbitrary
    
    ... ... @@ -163,52 +81,59 @@ instance Arbitrary FloatX4 where
    163 81
         FloatNT (F# f3) <- arbitrary
    
    164 82
         FloatNT (F# f4) <- arbitrary
    
    165 83
         return $ FX4# (packFloatX4# (# f1, f2, f3, f4 #))
    
    84
    +
    
    166 85
     instance Num FloatX4 where
    
    167
    -  FX4# x + FX4# y =
    
    168
    -    FX4# ( x `plusFloatX4#` y )
    
    169
    -  FX4# x - FX4# y =
    
    170
    -    FX4# ( x `minusFloatX4#` y )
    
    171
    -  negate ( FX4# x ) = FX4# ( negateFloatX4# x )
    
    172
    -  FX4# x * FX4# y =
    
    173
    -    FX4# ( x `timesFloatX4#` y )
    
    174
    -  abs = error "no"
    
    175
    -  signum = error "no"
    
    176
    -  fromInteger = error "no"
    
    86
    +  FX4# x + FX4# y = FX4# (x `plusFloatX4#`  y)
    
    87
    +  FX4# x - FX4# y = FX4# (x `minusFloatX4#` y)
    
    88
    +  negate (FX4# x) = FX4# (negateFloatX4# x)
    
    89
    +  FX4# x * FX4# y = FX4# (x `timesFloatX4#` y)
    
    90
    +  abs    = error "FloatX4: no abs"
    
    91
    +  signum = error "FloatX4: no signum"
    
    92
    +  fromInteger = error "FloatX4: no fromInteger"
    
    93
    +
    
    177 94
     instance HasMinMax FloatX4 where
    
    178 95
       mini (FX4# a) (FX4# b) = FX4# (minFloatX4# a b)
    
    179 96
       maxi (FX4# a) (FX4# b) = FX4# (maxFloatX4# a b)
    
    180 97
     
    
    98
    +--------------------------------------------------------------------------------
    
    99
    +
    
    181 100
     data DoubleX2 = DX2# DoubleX2#
    
    101
    +
    
    182 102
     instance Show DoubleX2 where
    
    183
    -  show (DX2# d) = case (unpackDoubleX2# d) of
    
    184
    -    (# a, b #) -> show ((D# a), (D# b))
    
    103
    +  show (DX2# d) = case unpackDoubleX2# d of
    
    104
    +    (# a, b #) -> show (D# a, D# b)
    
    105
    +
    
    185 106
     instance Eq DoubleX2 where
    
    186
    -  (DX2# a) == (DX2# b)
    
    187
    -    = case (unpackDoubleX2# a) of
    
    107
    +  DX2# a == DX2# b
    
    108
    +    = case unpackDoubleX2# a of
    
    188 109
             (# a1, a2 #) ->
    
    189
    -          case (unpackDoubleX2# b) of
    
    190
    -            (# b1, b2 #) -> DoubleNT (D# a1) == DoubleNT (D# b1) &&
    
    191
    -                            DoubleNT (D# a2) == DoubleNT (D# b2)
    
    110
    +          case unpackDoubleX2# b of
    
    111
    +            (# b1, b2 #) ->
    
    112
    +              DoubleNT (D# a1) == DoubleNT (D# b1) &&
    
    113
    +              DoubleNT (D# a2) == DoubleNT (D# b2)
    
    114
    +
    
    192 115
     instance Arbitrary DoubleX2 where
    
    193 116
       arbitrary = do
    
    194 117
         DoubleNT (D# d1) <- arbitrary
    
    195 118
         DoubleNT (D# d2) <- arbitrary
    
    196 119
         return $ DX2# (packDoubleX2# (# d1, d2 #))
    
    120
    +
    
    197 121
     instance Num DoubleX2 where
    
    198
    -  DX2# x + DX2# y =
    
    199
    -    DX2# ( x `plusDoubleX2#` y )
    
    200
    -  DX2# x - DX2# y =
    
    201
    -    DX2# ( x `minusDoubleX2#` y )
    
    202
    -  negate ( DX2# x ) = DX2# ( negateDoubleX2# x )
    
    203
    -  DX2# x * DX2# y =
    
    204
    -    DX2# ( x `timesDoubleX2#` y )
    
    205
    -  abs = error "no"
    
    206
    -  signum = error "no"
    
    207
    -  fromInteger = error "no"
    
    122
    +  DX2# x + DX2# y = DX2# (x `plusDoubleX2#`  y)
    
    123
    +  DX2# x - DX2# y = DX2# (x `minusDoubleX2#` y)
    
    124
    +  negate (DX2# x) = DX2# (negateDoubleX2# x)
    
    125
    +  DX2# x * DX2# y = DX2# (x `timesDoubleX2#` y)
    
    126
    +  abs    = error "DoubleX2: no abs"
    
    127
    +  signum = error "DoubleX2: no signum"
    
    128
    +  fromInteger = error "DoubleX2: no fromInteger"
    
    129
    +
    
    208 130
     instance HasMinMax DoubleX2 where
    
    209 131
       mini (DX2# a) (DX2# b) = DX2# (minDoubleX2# a b)
    
    210 132
       maxi (DX2# a) (DX2# b) = DX2# (maxDoubleX2# a b)
    
    211 133
     
    
    134
    +--------------------------------------------------------------------------------
    
    135
    +-- Expression language for generating random expressions over vector types.
    
    136
    +
    
    212 137
     data Expr a where
    
    213 138
       Lit :: a -> Expr a
    
    214 139
       Add :: Expr a -> Expr a -> Expr a
    
    ... ... @@ -218,11 +143,12 @@ data Expr a where
    218 143
       Min :: Expr a -> Expr a -> Expr a
    
    219 144
       Max :: Expr a -> Expr a -> Expr a
    
    220 145
       deriving (Show, Eq)
    
    146
    +
    
    221 147
     fmapExpr :: (a -> b) -> Expr a -> Expr b
    
    222
    -fmapExpr f (Lit a) = Lit (f a)
    
    148
    +fmapExpr f (Lit a)   = Lit (f a)
    
    223 149
     fmapExpr f (Add a b) = Add (fmapExpr f a) (fmapExpr f b)
    
    224 150
     fmapExpr f (Sub a b) = Sub (fmapExpr f a) (fmapExpr f b)
    
    225
    -fmapExpr f (Neg a) = Neg (fmapExpr f a)
    
    151
    +fmapExpr f (Neg a)   = Neg (fmapExpr f a)
    
    226 152
     fmapExpr f (Mul a b) = Mul (fmapExpr f a) (fmapExpr f b)
    
    227 153
     fmapExpr f (Min a b) = Min (fmapExpr f a) (fmapExpr f b)
    
    228 154
     fmapExpr f (Max a b) = Max (fmapExpr f a) (fmapExpr f b)
    
    ... ... @@ -240,75 +166,16 @@ instance Arbitrary a => Arbitrary (Expr a) where
    240 166
           _ -> Lit <$> arbitrary
    
    241 167
     
    
    242 168
     eval :: (Num a, HasMinMax a) => Expr a -> a
    
    243
    -eval (Lit a) = a
    
    169
    +eval (Lit a)   = a
    
    244 170
     eval (Add a b) = eval a + eval b
    
    245 171
     eval (Sub a b) = eval a - eval b
    
    246
    -eval (Neg a) = negate (eval a)
    
    172
    +eval (Neg a)   = negate (eval a)
    
    247 173
     eval (Mul a b) = eval a * eval b
    
    248 174
     eval (Min a b) = mini (eval a) (eval b)
    
    249 175
     eval (Max a b) = maxi (eval a) (eval b)
    
    250 176
     
    
    251
    -int64ToInt :: Int64 -> Int
    
    252
    -int64ToInt (I64# i) = I# (int64ToInt# i)
    
    253
    -
    
    254
    -
    
    255
    -word64ToWord :: Word64 -> Word
    
    256
    -word64ToWord (W64# i) = W# (word64ToWord# i)
    
    257
    -
    
    258
    -
    
    259
    -data RunS = RunS { depth :: Int, rg :: LCGGen  }
    
    260
    -
    
    261
    -newtype LCGGen = LCGGen { randomWord64 :: IO Word64 }
    
    262
    -
    
    263
    -data LCGParams = LCGParams { seed :: Word64, a :: Word64, c :: Word64, m :: Word64 }
    
    264
    -
    
    265
    -newLCGGen :: LCGParams -> IO LCGGen
    
    266
    -newLCGGen LCGParams{..}  = do
    
    267
    -  var <- newIORef (fromIntegral seed)
    
    268
    -  return $ LCGGen $ do
    
    269
    -    atomicModifyIORef' var (\old_v -> let new_val = (old_v * a + c) `mod` m in (new_val, new_val))
    
    270
    -
    
    271
    -
    
    272
    -runPropertyCheck (PropertyBinaryOp res desc s1 s2) =
    
    273
    -  if res then return True else (putMsg ("Failure: " ++ s1 ++ desc ++ s2) >> return False)
    
    274
    -runPropertyCheck (PropertyAnd a1 a2) = (&&) <$> runPropertyCheck a1 <*> runPropertyCheck a2
    
    275
    -
    
    276
    -runProperty :: Property -> ReaderT RunS IO ()
    
    277
    -runProperty (Prop p) = do
    
    278
    -  let iterations = 100
    
    279
    -  loop iterations iterations
    
    280
    -  where
    
    281
    -    loop iterations 0 = putMsg ("Passed " ++ show iterations ++ " iterations")
    
    282
    -    loop iterations n = do
    
    283
    -      h <- rg <$> ask
    
    284
    -      p <- liftIO (runReaderT (runGen p) h)
    
    285
    -      let (ss, pc) = getCheck p
    
    286
    -      res <- runPropertyCheck pc
    
    287
    -      if res then loop iterations (n-1)
    
    288
    -             else putMsg ("With arguments " ++ intercalate ", " ss)
    
    289
    -
    
    290
    -putMsg s = do
    
    291
    -  n <- depth <$> ask
    
    292
    -  liftIO . putStrLn $ replicate (n * 2) ' ' ++ s
    
    293
    -
    
    294
    -nest = local (\s -> s { depth = depth s + 1 })
    
    295
    -
    
    296
    -runTestInternal :: Test -> ReaderT RunS IO ()
    
    297
    -runTestInternal (Group name tests) = do
    
    298
    -  putMsg ("Group " ++ name)
    
    299
    -  nest (mapM_ runTestInternal tests)
    
    300
    -runTestInternal (Property name p) = do
    
    301
    -  putMsg ("Running " ++ name)
    
    302
    -  nest $ runProperty (property p)
    
    303
    -
    
    304
    -
    
    305
    -runTests :: Test -> IO ()
    
    306
    -runTests t = do
    
    307
    -  -- These params are the same ones as glibc uses.
    
    308
    -  h <- newLCGGen (LCGParams { seed = 1238123213, m = 2^31, a = 1103515245, c = 12345 })
    
    309
    -  runReaderT  (runTestInternal t) (RunS 0 h)
    
    310
    -
    
    311
    --------------------------------------------------------------------------------
    
    177
    +--------------------------------------------------------------------------------
    
    178
    +-- Test groups
    
    312 179
     
    
    313 180
     testFloatX4 :: Test
    
    314 181
     testFloatX4 = Group "FloatX4"
    
    ... ... @@ -324,15 +191,12 @@ testFloatX4 = Group "FloatX4"
    324 191
         unpack :: FloatX4 -> ( FloatNT, FloatNT, FloatNT, FloatNT )
    
    325 192
         unpack (FX4# f) = case unpackFloatX4# f of
    
    326 193
           (# f1, f2, f3, f4 #) -> coerce ( F# f1, F# f2, F# f3, F# f4 )
    
    194
    +
    
    327 195
         get1, get2, get3, get4 :: FloatX4 -> FloatNT
    
    328
    -    get1 (FX4# f) = case unpackFloatX4# f of
    
    329
    -      (# f1, _, _, _ #) -> FloatNT (F# f1)
    
    330
    -    get2 (FX4# f) = case unpackFloatX4# f of
    
    331
    -      (# _, f2, _, _ #) -> FloatNT (F# f2)
    
    332
    -    get3 (FX4# f) = case unpackFloatX4# f of
    
    333
    -      (# _, _, f3, _ #) -> FloatNT (F# f3)
    
    334
    -    get4 (FX4# f) = case unpackFloatX4# f of
    
    335
    -      (# _, _, _, f4 #) -> FloatNT (F# f4)
    
    196
    +    get1 (FX4# f) = case unpackFloatX4# f of (# f1,  _,  _,  _ #) -> FloatNT (F# f1)
    
    197
    +    get2 (FX4# f) = case unpackFloatX4# f of (#  _, f2,  _,  _ #) -> FloatNT (F# f2)
    
    198
    +    get3 (FX4# f) = case unpackFloatX4# f of (#  _,  _, f3,  _ #) -> FloatNT (F# f3)
    
    199
    +    get4 (FX4# f) = case unpackFloatX4# f of (#  _,  _,  _, f4 #) -> FloatNT (F# f4)
    
    336 200
     
    
    337 201
     testDoubleX2 :: Test
    
    338 202
     testDoubleX2 = Group "DoubleX2"
    
    ... ... @@ -346,16 +210,15 @@ testDoubleX2 = Group "DoubleX2"
    346 210
         unpack :: DoubleX2 -> ( DoubleNT, DoubleNT )
    
    347 211
         unpack (DX2# d) = case unpackDoubleX2# d of
    
    348 212
           (# d1, d2 #) -> coerce ( D# d1, D# d2 )
    
    213
    +
    
    349 214
         get1, get2 :: DoubleX2 -> DoubleNT
    
    350 215
         get1 (DX2# d) = case unpackDoubleX2# d of
    
    351
    -      (# d1, _ #) -> DoubleNT (D# d1)
    
    216
    +      (# d1,  _ #) -> DoubleNT (D# d1)
    
    352 217
         get2 (DX2# d) = case unpackDoubleX2# d of
    
    353
    -      (# _, d2 #) -> DoubleNT (D# d2)
    
    218
    +      (#  _, d2 #) -> DoubleNT (D# d2)
    
    354 219
     
    
    355 220
     testSIMD :: Test
    
    356
    -testSIMD = Group "ALL"
    
    357
    -    [ testFloatX4
    
    358
    -    , testDoubleX2
    
    359
    -    ]
    
    221
    +testSIMD = Group "ALL" [testFloatX4, testDoubleX2]
    
    360 222
     
    
    361
    -main = runTests testSIMD
    223
    +main :: IO ()
    
    224
    +main = runTestsMain (Iterations 100) testSIMD