1-- SPDX-FileCopyrightText: 2026 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Data.KTest6 ( KTest (..),7 KTestObj (..),8 fromAssign,9 )10where1112import Control.Monad (forM_, void, when)13import Data.Binary (Binary (get, put))14import Data.Binary.Get (getLazyByteString, getWord32be)15import Data.Binary.Put (putLazyByteString, putWord32be)16import Data.ByteString.Lazy qualified as BL17import Data.Map qualified as Map18import Data.String (fromString)19import Data.Word (Word32)20import Language.QBE.Backend.Store (Assign)21import Language.QBE.Simulator.Default.Expression qualified as DE22import Language.QBE.Simulator.Memory (toBytes)2324newtype KTestString25 = KTestString BL.ByteString26 deriving (Show, Eq)2728instance Binary KTestString where29 put (KTestString bs) =30 putWord32be (fromIntegral $ BL.length bs) >> putLazyByteString bs3132 get = do33 len <- getWord32be34 str <- getLazyByteString (fromIntegral len)35 pure $ KTestString str3637------------------------------------------------------------------------3839data KTestObj40 = KTestObj41 { objName :: BL.ByteString,42 objBytes :: BL.ByteString43 }44 deriving (Show, Eq)4546instance Binary KTestObj where47 put (KTestObj name bytes) = do48 put (KTestString name)49 put (KTestString bytes)5051 get = do52 (KTestString name) <- get53 (KTestString bytes) <- get54 pure $ KTestObj name bytes5556fromAssign :: Assign -> [KTestObj]57fromAssign assign = map go $ Map.toList assign58 where59 go :: (String, DE.RegVal) -> KTestObj60 go (name, value) =61 KTestObj (fromString name) (BL.pack $ toBytes value)6263------------------------------------------------------------------------6465data KTest66 = KTest67 { ktArgs :: [BL.ByteString],68 ktObjs :: [KTestObj]69 }70 deriving (Show, Eq)7172header :: BL.ByteString73header = fromString "KTEST"7475legacyHeader :: BL.ByteString76legacyHeader = fromString "BOUT\n"7778version :: Word3279version = 38081instance Binary KTest where82 get = do83 hdr <- getLazyByteString (BL.length header)84 when (hdr /= header && hdr /= legacyHeader) $85 fail "invalid ktest header"86 ver <- getWord32be87 when (ver > version) $88 fail "unsupported ktest version"8990 numArgs <- getWord32be91 strs <-92 mapM93 ( \_ -> do94 (KTestString s) <- get95 pure s96 )97 [1 .. numArgs]9899 when (ver >= 2) $100 -- XXX: Skip symArgvs and symArgvLen for now.101 void (getWord32be >> getWord32be)102103 numObjs <- getWord32be104 objs <- mapM (const get) [1 .. numObjs]105106 pure $ KTest strs objs107108 put (KTest args objs) = do109 putLazyByteString header110 putWord32be version111112 putWord32be (fromIntegral $ length args)113 forM_ args (put . KTestString)114115 -- XXX: Skip symArgvs and symArgvLen for now.116 putWord32be 0117 putWord32be 0118119 putWord32be (fromIntegral $ length objs)120 forM_ objs put