{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-} -- Test allocation of statically sized arrays. There's an optimization -- that targets these and we want to make sure that the code generated -- in the optimized case is correct. -- -- The tests proceeds by allocating a bunch of arrays of different -- sizes and reading elements from them, to try to provoke GC crashes, -- which would be a symptom of the optimization not generating correct -- code. module Main where import Control.Monad import GHC.Exts import GHC.IO import Prelude hiding (read) main :: IO () main = do loop 1000 putStrLn "success" where loop :: Int -> IO () loop 0 = return () loop i = do -- Sizes have been picked to match the triggering of the -- optimization and to match boundary conditions. Sizes are -- given explicitly as to not rely on other optimizations to -- make the static size known to the compiler. marr0 <- newArray 0 marr1 <- newArray 1 marr2 <- newArray 2 marr3 <- newArray 3 marr4 <- newArray 4 marr5 <- newArray 5 marr6 <- newArray 6 marr7 <- newArray 7 marr8 <- newArray 8 marr9 <- newArray 9 marr10 <- newArray 10 marr11 <- newArray 11 marr12 <- newArray 12 marr13 <- newArray 13 marr14 <- newArray 14 marr15 <- newArray 15 marr16 <- newArray 16 marr17 <- newArray 17 let marrs = [marr0, marr1, marr2, marr3, marr4, marr5, marr6, marr7, marr8, marr9, marr10, marr11, marr12, marr13, marr14, marr15, marr16, marr17] total <- sumManyArrays marrs unless (total == 153) $ putStrLn "incorrect sum" loop (i-1) sumManyArrays :: [MArray] -> IO Int sumManyArrays = go 0 where go !acc [] = return acc go acc (marr:marrs) = do n <- sumArray marr go (acc+n) marrs sumArray :: MArray -> IO Int sumArray marr = go 0 0 where go :: Int -> Int -> IO Int go !acc i | i < len = do k <- read marr i go (acc + k) (i+1) | otherwise = return acc len = lengthM marr data MArray = MArray { unMArray :: !(MutableArray# RealWorld Int) } newArray :: Int -> IO MArray newArray (I# sz#) = IO $ \s -> case newArray# sz# 1 s of (# s', marr #) -> (# s', MArray marr #) {-# INLINE newArray #-} -- to make sure optimization triggers lengthM :: MArray -> Int lengthM marr = I# (sizeofMutableArray# (unMArray marr)) read :: MArray -> Int -> IO Int read marr i@(I# i#) | i < 0 || i >= len = error $ "bounds error, offset " ++ show i ++ ", length " ++ show len | otherwise = IO $ \ s -> readArray# (unMArray marr) i# s where len = lengthM marr