import System.Process import System.Exit import System.IO import Data.List import Data.Maybe import System.Directory import Control.Monad import Control.Concurrent import qualified Control.Exception as C import Text.Printf import Text.Regex.PCRE.Light.Char8 ------------------------------------------------------------------------ flags= [["-O","-fspec-constr"] ,["-O2"] ] tests = [(Just 2, "cons", flags ) -- expect 2 fusions, with -O2 and -O ,(Just 2, "snoc", flags ) ,(Just 2, "empty", flags ) -- ,(Just 1, "from-to", flags ) ,(Just 2, "singleton", flags ) ,(Just 4, "map", flags ) ,(Just 5, "filter", flags ) ,(Just 2, "replicate", flags ) ,(Just 2, "takeWhile", flags ) ,(Just 2, "index", flags ) ,(Just 3, "null", flags ) ,(Just 1, "length", flags ) ,(Just 1, "length-bool", flags ) ,(Just 1, "length-unit", flags ) ,(Just 1, "length-char", flags ) ,(Just 1, "length-word", flags ) ,(Just 1, "length-word8", flags ) ,(Just 1, "length-word16", flags ) ,(Just 1, "length-word32", flags ) ,(Just 1, "length-word64", flags ) ,(Just 1, "length-int8", flags ) ,(Just 1, "length-int16", flags ) ,(Just 1, "length-int32", flags ) ,(Just 1, "length-int64", flags ) ,(Just 1, "length-double", flags ) ,(Just 1, "length-float", flags ) ,(Just 2, "head", flags ) ,(Just 4, "append", flags ) ,(Just 3, "sum", flags ) ,(Just 3, "product", flags ) ,(Just 1, "and", flags ) ,(Just 1, "or", flags ) ,(Just 2, "elem", flags ) ,(Just 2, "tail", flags ) ,(Just 2, "find", flags ) ,(Just 2, "findIndex", flags ) ,(Just 2, "init", flags ) ,(Just 2, "last", flags ) ,(Just 3, "foldl1", flags ) ,(Just 3, "minimum", flags ) ,(Just 3, "maximum", flags ) ,(Just 3, "maximumBy", flags ) ,(Just 3, "minimumBy", flags ) ,(Just 2, "take", flags ) ,(Just 2, "drop", flags ) ,(Just 4, "zipwith", flags ) ,(Just 4, "zipwith3", flags ) ,(Just 3, "zip", flags ) -- expect zipU fusion ,(Just 3, "indexed", flags ) -- failing ,(Just 1, "unfold", flags ) -- failing ] ------------------------------------------------------------------------ main = do printf "Running %d fusion tests.\n" (length tests) vs <- forM tests $ \x -> do v <- run x putChar '\n' return v printf "\nDone.\n" if not (and vs) then exitWith (ExitFailure 1) else return () run :: (Maybe Int, String, [[String]]) -> IO Bool run (n, name, args) = do printf "%20s: " name >> hFlush stdout v <- forM args $ \opt -> do putChar '.' >> hFlush stdout (cmd,ex,fusion) <- compile_program name opt if ex /= n then do printf "\n%s failed to trigger fusion. Expected %s, Actual %s.\n" name (show n) (show ex) printf "Command line: %s\n" (show $ intercalate " " cmd) return False else if isJust fusion then do printf "\n%s failed to remove all vectors.\n" name printf "Remnants: %s\n" (show fusion) printf "Command line: %s\n" (show $ intercalate " " cmd) return False else return True return (and v) ------------------------------------------------------------------------ compile_program s opt = do let command = [(s ++ ".hs"), "-ddump-simpl","-ddump-simpl-stats","-no-recomp","--make"] ++ opt x <- readProcess "ghc" command [] removeFile s case x of Left (err,str) -> do print str printf "GHC failed to compile %s\n" s exitWith (ExitFailure 1) -- fatal Right str -> do return $ case match fusion_regex str [] of Nothing -> (command,Nothing,Nothing) Just xs -> let fusion_result = (read $ last xs) in case match left_over_vector str [] of Nothing -> (command, Just fusion_result, Nothing) Just n -> (command, Just fusion_result, Just n) ------------------------------------------------------------------------ -- Fusion happened fusion_regex = compile "(\\d+).*streamU/unstreamU" [] -- Data.Array.Vector.Strict.Prim.UVec -- UVectors were left behind left_over_vector = compile "Data\\.Array\\.Vector\\.Unlifted\\.UArr\\.UArr|Data\\.Array\\.Vector\\.Base\\.Rebox\\.Box" [] ------------------------------------------------------------------------ -- Also, bytestring input/output, since we're strict -- Document that this isn't for interactive -- -- | readProcess forks an external process, reads its standard output -- strictly, blocking until the process terminates, and returns either the output -- string, or, in the case of non-zero exit status, an error code, and -- any output. -- -- Output is returned strictly, so this is not suitable for -- interactive applications. -- -- Users of this library should compile with -threaded if they -- want other Haskell threads to keep running while waiting on -- the result of readProcess. -- -- > > readProcess "date" [] [] -- > Right "Thu Feb 7 10:03:39 PST 2008\n" -- -- The argumenst are: -- -- * The command to run, which must be in the $PATH, or an absolute path -- -- * A list of separate command line arguments to the program -- -- * A string to pass on the standard input to the program. -- readProcess :: FilePath -- ^ command to run -> [String] -- ^ any arguments -> String -- ^ standard input -> IO (Either (ExitCode,String) String) -- ^ either the stdout, or an exitcode and any output readProcess cmd args input = C.handle (return . handler) $ do (inh,outh,errh,pid) <- runInteractiveProcess cmd args Nothing Nothing output <- hGetContents outh outMVar <- newEmptyMVar forkIO $ (C.evaluate (length output) >> putMVar outMVar ()) when (not (null input)) $ hPutStr inh input takeMVar outMVar ex <- C.catch (waitForProcess pid) (\_e -> return ExitSuccess) hClose outh hClose inh -- done with stdin hClose errh -- ignore stderr return $ case ex of ExitSuccess -> Right output ExitFailure _ -> Left (ex, output) where handler (C.ExitException e) = Left (e,"") handler e = Left (ExitFailure 1, show e)