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.Backend.Store qualified as ST11import Language.QBE.Backend.Tracer qualified as T12import Language.QBE.Simulator.Concolic.State (mkEnv)13import Language.QBE.Simulator.Explorer (explore, logSolver, newEngine)14import Language.QBE.Types qualified as QBE15import SMTUnwind (unwind)16import System.Exit (ExitCode (ExitSuccess))17import System.FilePath ((</>))18import System.IO (IOMode (WriteMode), hClose, hPutStrLn, openFile, withFile)19import System.Process20 ( StdStream (CreatePipe, UseHandle),21 createProcess,22 proc,23 std_in,24 std_out,25 waitForProcess,26 )2728logPath :: FilePath29logPath = "/tmp/quebex-symex-bench.smt2"3031entryFunc :: QBE.GlobalIdent32entryFunc = QBE.GlobalIdent "main"3334------------------------------------------------------------------------3536exploreQBE :: FilePath -> IO [(ST.Assign, T.ExecTrace)]37exploreQBE filePath = do38 (prog, func) <- readFile filePath >>= parseAndFind entryFunc3940 withFile logPath WriteMode (explore' prog func)41 where42 explore' prog func handle = do43 engine <- newEngine <$> logSolver handle44 defEnv <- mkEnv prog 0 128 (Just 0)45 explore engine defEnv func []4647getQueries :: String -> IO String48getQueries name = do49 _ <- exploreQBE ("bench" </> "data" </> "SMT" </> name)50 -- XXX: Uncomment this to benchmark incremental solving instead.51 unwind logPath5253solveQueries :: String -> IO ()54solveQueries queries = do55 devNull <- openFile "/dev/null" WriteMode56 (Just hin, _, _, p) <-57 createProcess58 (proc "bitwuzla" [])59 { std_in = CreatePipe,60 std_out = UseHandle devNull61 }6263 hPutStrLn hin queries <* hClose hin64 ret <- waitForProcess p <* hClose devNull65 when (ret /= ExitSuccess) $66 error "SMT solver failed"6768smtBench :: Benchmark69smtBench = do70 bgroup71 "SMT Complexity"72 [ benchWithEnv "prime-numbers.qbe",73 benchWithEnv "bubble-sort.qbe",74 benchWithEnv "insertion-sort-uchar.qbe"75 ]76 where77 benchSolver :: String -> String -> Benchmark78 benchSolver name queries = bench name $ nfIO (solveQueries queries)7980 benchWithEnv :: String -> Benchmark81 benchWithEnv name = env (getQueries name) (benchSolver name)