{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE MonadComprehensions #-}
module Tests.RegAlloc where
import Control.Monad ((>=>), guard)
import Control.Monad.Logic.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Control.Monad.Trans.Reader
import Data.Bool (bool)
import qualified Data.Foldable.Unicode as Foldable
import Data.Function (on)
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import GHC.Generics
import Test.SmallCheck.Series hiding ((<~>))
import Test.Tasty (TestTree)
import Test.Tasty.SmallCheck
import RegAlloc
import RegAlloc.Interference as If
import RegAlloc.UGraph as UGr
import RegAlloc.Nodes as Nodes
import RegAlloc.Nodes.Private
test :: TestTree
test = testProperty "allocRegs" \ (Problem { regCount, ifs, moves }) ->
case runExcept $ (allocRegs' regCount ifs >=> uncurry (colorize regCount ifs)) moves of
Left _ -> Right ""
Right colors -> "" <$ runExcept do
bool (throwE $ "bad register: " ++ show colors) (pure ()) $ all (< regCount) colors
bool (throwE $ "bad domain: " ++ show colors) (pure ()) $ IM.keysSet colors == IS.fromAscList (fst <$> If.toAscList ifs)
bool (throwE $ "bad answer: " ++ show colors) (pure ()) $ flip all (IM.toList colors) \ (k, color) ->
let nbrColors = (\ case Node k -> colors IM.! k; Precolored c -> c) <$> Nodes.toList (nbrsOf k ifs)
in color Foldable.∉ nbrColors
data Problem = Problem
{ regCount, nodeCount :: !Int, ifs :: !Interferences, moves :: !UGraph }
deriving (Eq, Show, Generic)
instance Monad m => Serial m Problem where
series = series >>- \ parms@(Parms { regCount, nodeCount }) -> flip runReaderT parms $
[Problem {..} | (ifs, moves) <- (,) <$> ugrSeries <~> ugrSeries]
data Parms = Parms
{ regCount, nodeCount :: !Int }
deriving (Eq, Show, Generic)
deriving instance Monad m => Serial m Parms
ugrSeries :: Monad m => ReaderT Parms (Series m) UGraph
ugrSeries = do
Parms { nodeCount } <- ask
flip UGr.insertEdges (UGr.empty nodeCount) <$> mapReaderT (sortedListSBy p) edgeSeries
where p = (<) `on` \ (Node_ i, j) -> (i, j)
edgeSeries :: Monad m => ReaderT Parms (Series m) (Node, Int)
edgeSeries = do
Parms { nodeCount } <- ask
k' <- nodeSeries
lift $ getNonNegative <$> series >>- \ k ->
(k', k) <$ guard (unNode_ k' < k && k < nodeCount)
nodeSeries :: Monad m => ReaderT Parms (Series m) Node
nodeSeries = do
Parms { regCount, nodeCount } <- ask
lift $ Node_ <$> rangeS (-regCount, nodeCount)
sortedListSBy :: Monad m => (a -> a -> Bool) -> Series m a -> Series m [a]
sortedListSBy p as = decDepth (pure []) `interleave` decDepth (as >>- go) where
go a = (:) a <$> decDepth (pure [] `interleave` do b <- as; guard (p a b); go b)
rangeS :: Monad m => (Int, Int) -> Series m Int
rangeS (a, b) = do
k <- series
k <$ guard (k >= a && k < b)
infixl 4 <~>
(<~>) :: MonadLogic m => m (a -> b) -> m a -> m b
a <~> b = a >>- (<$> b)