1-- SPDX-FileCopyrightText: 2025-2026 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Language.QBE.Types where67import Control.Monad (foldM)8import Data.Map (Map)9import Data.Word (Word64)1011-- TODO: Prefix all constructors1213newtype UserIdent = UserIdent {userIdent :: String}14 deriving (Eq, Ord)1516instance Show UserIdent where17 show (UserIdent s) = ':' : s1819newtype LocalIdent = LocalIdent {localIdent :: String}20 deriving (Eq, Ord)2122instance Show LocalIdent where23 show (LocalIdent s) = '%' : s2425newtype BlockIdent = BlockIdent {blockIdent :: String}26 deriving (Eq, Ord)2728instance Show BlockIdent where29 show (BlockIdent s) = '@' : s3031newtype GlobalIdent = GlobalIdent {globalIdent :: String}32 deriving (Eq, Ord)3334instance Show GlobalIdent where35 show (GlobalIdent s) = '$' : s3637------------------------------------------------------------------------3839data BaseType40 = Word41 | Long42 | Single43 | Double44 deriving (Show, Eq)4546baseTypeByteSize :: BaseType -> Int47baseTypeByteSize Word = 448baseTypeByteSize Long = 849baseTypeByteSize Single = 450baseTypeByteSize Double = 85152baseTypeBitSize :: BaseType -> Int53baseTypeBitSize ty = baseTypeByteSize ty * 85455data ExtType56 = Base BaseType57 | Byte58 | HalfWord59 deriving (Show, Eq)6061extTypeByteSize :: ExtType -> Int62extTypeByteSize (Base b) = baseTypeByteSize b63extTypeByteSize Byte = 164extTypeByteSize HalfWord = 26566extTypeBitSize :: ExtType -> Int67extTypeBitSize ty = extTypeByteSize ty * 86869data SubWordType70 = SignedByte71 | UnsignedByte72 | SignedHalf73 | UnsignedHalf74 deriving (Show, Eq)7576data Abity77 = ABase BaseType78 | ASubWordType SubWordType79 | AUserDef UserIdent80 deriving (Show, Eq)8182abityToBase :: Abity -> BaseType83-- Calls with a sub-word return type define a temporary of base type84-- w with its most significant bits unspecified.85abityToBase (ASubWordType _) = Word86-- When an aggregate type is used as argument type or return type, the87-- value respectively passed or returned needs to be a pointer to a88-- memory location holding the value.89abityToBase (AUserDef _) = Long90abityToBase (ABase ty) = ty9192data Const93 = Number Word6494 | SFP Float95 | DFP Double96 | Global GlobalIdent97 deriving (Show, Eq)9899data DynConst100 = Const Const101 | Thread GlobalIdent102 | Extern GlobalIdent103 | ExternThread GlobalIdent104 deriving (Show, Eq)105106data Value107 = VConst DynConst108 | VLocal LocalIdent109 deriving (Show, Eq)110111data Linkage112 = LExport113 | LThread114 | LSection String (Maybe String)115 deriving (Show, Eq)116117data AllocSize118 = AllocWord119 | AllocLong120 | AllocLongLong121 deriving (Show, Eq)122123getSize :: AllocSize -> Int124getSize AllocWord = 4125getSize AllocLong = 8126getSize AllocLongLong = 16127128data TypeDef129 = TypeDef130 { aggName :: UserIdent,131 aggAlign :: Maybe Word64,132 aggType :: AggType133 }134 deriving (Show, Eq)135136data SubType137 = SExtType ExtType138 | SUserDef UserIdent139 deriving (Show, Eq)140141type Field = (SubType, Maybe Word64)142143-- TODO: Type for tuple144data AggType145 = ARegular [Field]146 | AUnion [[Field]]147 | AOpaque Word64148 deriving (Show, Eq)149150data DataDef151 = DataDef152 { linkage :: [Linkage],153 name :: GlobalIdent,154 align :: Maybe Word64,155 objs :: [DataObj]156 }157 deriving (Show, Eq)158159dataSize :: DataDef -> Int160dataSize dataDef =161 sum $ map objSize (objs dataDef)162163data DataObj164 = OItem ExtType [DataItem]165 | OZeroFill Word64166 deriving (Show, Eq)167168objAlign :: DataObj -> Word64169objAlign (OZeroFill _) = 1 :: Word64170objAlign (OItem ty _) = fromIntegral $ extTypeByteSize ty171172objSize :: DataObj -> Int173objSize (OZeroFill n) = fromIntegral n174objSize (OItem ty items) = extTypeByteSize ty * cnt items175 where176 cnt :: [DataItem] -> Int177 cnt [] = 0178 cnt ((DString s) : xs) = length s + cnt xs179 cnt (_ : xs) = 1 + cnt xs180181data DataItem182 = DSymOff GlobalIdent Word64183 | DString String184 | DConst Const185 deriving (Show, Eq)186187data FuncDef188 = FuncDef189 { fLinkage :: [Linkage],190 fName :: GlobalIdent,191 fAbity :: Maybe Abity,192 fParams :: [FuncParam],193 fBlock :: [Block] -- TODO: Use a Map here194 }195 deriving (Show, Eq)196197data FuncParam198 = Regular Abity LocalIdent199 | Env LocalIdent200 | Variadic201 deriving (Show, Eq)202203data FuncArg204 = ArgReg Abity Value205 | ArgEnv Value206 | ArgVar207 deriving (Show, Eq)208209data JumpInstr210 = Jump BlockIdent211 | Jnz Value BlockIdent BlockIdent212 | Return (Maybe Value)213 | Halt214 deriving (Show, Eq)215216data LoadType217 = LSubWord SubWordType218 | LBase BaseType219 deriving (Show, Eq)220221-- TODO: Could/Should define this on ExtType instead.222loadByteSize :: LoadType -> Word64223loadByteSize (LSubWord UnsignedByte) = 1224loadByteSize (LSubWord SignedByte) = 1225loadByteSize (LSubWord SignedHalf) = 2226loadByteSize (LSubWord UnsignedHalf) = 2227loadByteSize (LBase Word) = 4228loadByteSize (LBase Long) = 8229loadByteSize (LBase Single) = 4230loadByteSize (LBase Double) = 8231232data ExtArg233 = ExtSingle234 | ExtSubWord SubWordType235 | ExtSignedWord236 | ExtUnsignedWord237 deriving (Show, Eq)238239toExtType :: ExtArg -> (Bool, ExtType)240toExtType (ExtSubWord SignedByte) = (True, Byte)241toExtType (ExtSubWord UnsignedByte) = (False, Byte)242toExtType (ExtSubWord SignedHalf) = (True, HalfWord)243toExtType (ExtSubWord UnsignedHalf) = (False, HalfWord)244toExtType ExtSignedWord = (True, Base Word)245toExtType ExtUnsignedWord = (False, Base Word)246toExtType ExtSingle = (True, Base Single)247248data FloatArg = FDouble | FSingle249 deriving (Show, Eq)250251f2BaseType :: FloatArg -> BaseType252f2BaseType FSingle = Single253f2BaseType FDouble = Double254255data IntArg = IWord | ILong256 deriving (Show, Eq)257258i2BaseType :: IntArg -> BaseType259i2BaseType IWord = Word260i2BaseType ILong = Long261262-- TODO: Distinict types for floating point comparison?263data IntCmpOp264 = IEq265 | INe266 | ISle267 | ISlt268 | ISge269 | ISgt270 | IUle271 | IUlt272 | IUge273 | IUgt274 deriving (Show, Eq)275276data FloatCmpOp277 = FEq278 | FNe279 | FLe280 | FLt281 | FGe282 | FGt283 | FOrd284 | FUnord285 deriving (Show, Eq)286287data Instr288 = Add Value Value289 | Sub Value Value290 | Div Value Value291 | Mul Value Value292 | Neg Value293 | URem Value Value294 | Rem Value Value295 | UDiv Value Value296 | Or Value Value297 | Xor Value Value298 | And Value Value299 | Sar Value Value300 | Shr Value Value301 | Shl Value Value302 | Alloc AllocSize Value303 | Load LoadType Value304 | CompareInt IntArg IntCmpOp Value Value305 | CompareFloat FloatArg FloatCmpOp Value Value306 | Ext ExtArg Value307 | FloatToInt FloatArg Bool Value308 | IntToFloat IntArg Bool Value309 | TruncDouble Value310 | Cast Value311 | Copy Value312 | VAArg Value313 deriving (Show, Eq)314315data VolatileInstr316 = Store ExtType Value Value317 | VAStart Value318 | Blit Value Value Word64319 | DBGLoc Word64 Word64 (Maybe Word64)320 deriving (Show, Eq)321322data Statement323 = Assign LocalIdent BaseType Instr324 | Call (Maybe (LocalIdent, Abity)) Value [FuncArg]325 | Volatile VolatileInstr326 deriving (Show, Eq)327328data Phi329 = Phi330 { pName :: LocalIdent,331 pType :: BaseType,332 pLabels :: Map BlockIdent Value333 }334 deriving (Show, Eq)335336data Block'337 = Block'338 { label' :: BlockIdent,339 phi' :: [Phi],340 stmt' :: [Statement],341 term' :: Maybe JumpInstr342 }343 deriving (Show, Eq)344345insertJumps :: [Block'] -> Maybe [Block]346insertJumps xs = foldM go [] $ zipWithNext xs347 where348 zipWithNext :: [a] -> [(a, Maybe a)]349 zipWithNext [] = []350 zipWithNext lst@(_ : t) = zip lst $ map Just t ++ [Nothing]351352 fromBlock' :: Block' -> JumpInstr -> Block353 fromBlock' (Block' l p s _) = Block l p s354355 go :: [Block] -> (Block', Maybe Block') -> Maybe [Block]356 go acc (x@Block' {term' = Just ji}, _) =357 Just (acc ++ [fromBlock' x ji])358 go acc (x@Block' {term' = Nothing}, Just nxt) =359 Just (acc ++ [fromBlock' x (Jump $ label' nxt)])360 go _ (Block' {term' = Nothing}, Nothing) =361 Nothing362363data Block364 = Block365 { label :: BlockIdent,366 phi :: [Phi],367 stmt :: [Statement],368 term :: JumpInstr369 }370 deriving (Show, Eq)