1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: MIT AND GPL-3.0-only45module SMT (smtBench) where67import Control.Monad (when)8import Criterion.Main9import Language.QBE (parseAndFind)10import Language.QBE.Simulator.Concolic.State (mkEnv)11import Language.QBE.Simulator.Explorer (PathResult, exploreFunc, logSolver, newEngine)12import Language.QBE.Types qualified as QBE13import SMTUnwind (unwind)14import System.Exit (ExitCode (ExitSuccess))15import System.FilePath ((</>))16import System.IO (IOMode (WriteMode), hClose, hPutStrLn, openFile, withFile)17import System.Process18 ( StdStream (CreatePipe, UseHandle),19 createProcess,20 proc,21 std_in,22 std_out,23 waitForProcess,24 )2526logPath :: FilePath27logPath = "/tmp/quebex-symex-bench.smt2"2829entryFunc :: QBE.GlobalIdent30entryFunc = QBE.GlobalIdent "main"3132------------------------------------------------------------------------3334exploreQBE :: FilePath -> IO [PathResult]35exploreQBE filePath = do36 (prog, func) <- readFile filePath >>= parseAndFind entryFunc3738 withFile logPath WriteMode (exploreFunc' prog func)39 where40 exploreFunc' prog func handle = do41 defEnv <- mkEnv prog 0 128 (Just 0)42 engine <- newEngine defEnv <$> logSolver handle43 exploreFunc engine func []4445getQueries :: String -> IO String46getQueries name = do47 _ <- exploreQBE ("bench" </> "data" </> "SMT" </> name)48 -- XXX: Uncomment this to benchmark incremental solving instead.49 unwind logPath5051solveQueries :: String -> IO ()52solveQueries queries = do53 devNull <- openFile "/dev/null" WriteMode54 (Just hin, _, _, p) <-55 createProcess56 (proc "bitwuzla" [])57 { std_in = CreatePipe,58 std_out = UseHandle devNull59 }6061 hPutStrLn hin queries <* hClose hin62 ret <- waitForProcess p <* hClose devNull63 when (ret /= ExitSuccess) $64 error "SMT solver failed"6566smtBench :: Benchmark67smtBench = do68 bgroup69 "SMT Complexity"70 [ benchWithEnv "prime-numbers.qbe",71 benchWithEnv "bubble-sort.qbe",72 benchWithEnv "insertion-sort-uchar.qbe"73 ]74 where75 benchSolver :: String -> String -> Benchmark76 benchSolver name queries = bench name $ nfIO (solveQueries queries)7778 benchWithEnv :: String -> Benchmark79 benchWithEnv name = env (getQueries name) (benchSolver name)