quebex

A software analysis framework built around the QBE intermediate language

git clone https://git.8pit.net/quebex.git

  1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>
  2--
  3-- SPDX-License-Identifier: GPL-3.0-only
  4
  5module Language.QBE.Types where
  6
  7import Control.Monad (foldM)
  8import Data.Map (Map)
  9import Data.Word (Word64)
 10
 11-- TODO: Prefix all constructors
 12
 13newtype UserIdent = UserIdent {userIdent :: String}
 14  deriving (Eq, Ord)
 15
 16instance Show UserIdent where
 17  show (UserIdent s) = ':' : s
 18
 19newtype LocalIdent = LocalIdent {localIdent :: String}
 20  deriving (Eq, Ord)
 21
 22instance Show LocalIdent where
 23  show (LocalIdent s) = '%' : s
 24
 25newtype BlockIdent = BlockIdent {blockIdent :: String}
 26  deriving (Eq, Ord)
 27
 28instance Show BlockIdent where
 29  show (BlockIdent s) = '@' : s
 30
 31newtype GlobalIdent = GlobalIdent {globalIdent :: String}
 32  deriving (Eq, Ord)
 33
 34instance Show GlobalIdent where
 35  show (GlobalIdent s) = '$' : s
 36
 37------------------------------------------------------------------------
 38
 39data BaseType
 40  = Word
 41  | Long
 42  | Single
 43  | Double
 44  deriving (Show, Eq)
 45
 46baseTypeByteSize :: BaseType -> Int
 47baseTypeByteSize Word = 4
 48baseTypeByteSize Long = 8
 49baseTypeByteSize Single = 4
 50baseTypeByteSize Double = 8
 51
 52baseTypeBitSize :: BaseType -> Int
 53baseTypeBitSize ty = baseTypeByteSize ty * 8
 54
 55data ExtType
 56  = Base BaseType
 57  | Byte
 58  | HalfWord
 59  deriving (Show, Eq)
 60
 61extTypeByteSize :: ExtType -> Int
 62extTypeByteSize (Base b) = baseTypeByteSize b
 63extTypeByteSize Byte = 1
 64extTypeByteSize HalfWord = 2
 65
 66extTypeBitSize :: ExtType -> Int
 67extTypeBitSize ty = extTypeByteSize ty * 8
 68
 69data SubWordType
 70  = SignedByte
 71  | UnsignedByte
 72  | SignedHalf
 73  | UnsignedHalf
 74  deriving (Show, Eq)
 75
 76data Abity
 77  = ABase BaseType
 78  | ASubWordType SubWordType
 79  | AUserDef UserIdent
 80  deriving (Show, Eq)
 81
 82abityToBase :: Abity -> BaseType
 83-- Calls with a sub-word return type define a temporary of base type
 84-- w with its most significant bits unspecified.
 85abityToBase (ASubWordType _) = Word
 86-- When an aggregate type is used as argument type or return type, the
 87-- value respectively passed or returned needs to be a pointer to a
 88-- memory location holding the value.
 89abityToBase (AUserDef _) = Long
 90abityToBase (ABase ty) = ty
 91
 92data Const
 93  = Number Word64
 94  | SFP Float
 95  | DFP Double
 96  | Global GlobalIdent
 97  deriving (Show, Eq)
 98
 99data DynConst
100  = Const Const
101  | Thread GlobalIdent
102  deriving (Show, Eq)
103
104data Value
105  = VConst DynConst
106  | VLocal LocalIdent
107  deriving (Show, Eq)
108
109data Linkage
110  = LExport
111  | LThread
112  | LSection String (Maybe String)
113  deriving (Show, Eq)
114
115data AllocSize
116  = AlignWord
117  | AlignLong
118  | AlignLongLong
119  deriving (Show, Eq)
120
121getSize :: AllocSize -> Int
122getSize AlignWord = 4
123getSize AlignLong = 8
124getSize AlignLongLong = 16
125
126data TypeDef
127  = TypeDef
128  { aggName :: UserIdent,
129    aggAlign :: Maybe AllocSize,
130    aggType :: AggType
131  }
132  deriving (Show, Eq)
133
134data SubType
135  = SExtType ExtType
136  | SUserDef UserIdent
137  deriving (Show, Eq)
138
139type Field = (SubType, Maybe Word64)
140
141-- TODO: Type for tuple
142data AggType
143  = ARegular [Field]
144  | AUnion [[Field]]
145  | AOpaque Word64
146  deriving (Show, Eq)
147
148data DataDef
149  = DataDef
150  { linkage :: [Linkage],
151    name :: GlobalIdent,
152    align :: Maybe AllocSize,
153    objs :: [DataObj]
154  }
155  deriving (Show, Eq)
156
157data DataObj
158  = OItem ExtType [DataItem]
159  | OZeroFill Word64
160  deriving (Show, Eq)
161
162data DataItem
163  = DSymbol GlobalIdent (Maybe Word64)
164  | DString String
165  | DConst Const
166  deriving (Show, Eq)
167
168data FuncDef
169  = FuncDef
170  { fLinkage :: [Linkage],
171    fName :: GlobalIdent,
172    fAbity :: Maybe Abity,
173    fParams :: [FuncParam],
174    fBlock :: [Block] -- TODO: Use a Map here
175  }
176  deriving (Show, Eq)
177
178data FuncParam
179  = Regular Abity LocalIdent
180  | Env LocalIdent
181  | Variadic
182  deriving (Show, Eq)
183
184data FuncArg
185  = ArgReg Abity Value
186  | ArgEnv Value
187  | ArgVar
188  deriving (Show, Eq)
189
190data JumpInstr
191  = Jump BlockIdent
192  | Jnz Value BlockIdent BlockIdent
193  | Return (Maybe Value)
194  | Halt
195  deriving (Show, Eq)
196
197data LoadType
198  = LSubWord SubWordType
199  | LBase BaseType
200  deriving (Show, Eq)
201
202-- TODO: Could/Should define this on ExtType instead.
203loadByteSize :: LoadType -> Word64
204loadByteSize (LSubWord UnsignedByte) = 1
205loadByteSize (LSubWord SignedByte) = 1
206loadByteSize (LSubWord SignedHalf) = 2
207loadByteSize (LSubWord UnsignedHalf) = 2
208loadByteSize (LBase Word) = 4
209loadByteSize (LBase Long) = 8
210loadByteSize (LBase Single) = 4
211loadByteSize (LBase Double) = 8
212
213data SubLongType
214  = SLSubWord SubWordType
215  | SLSignedWord
216  | SLUnsignedWord
217  deriving (Show, Eq)
218
219-- TODO: Distinict types for floating point comparison?
220data CmpOp
221  = CEq
222  | CNe
223  | CSle
224  | CSlt
225  | CSge
226  | CSgt
227  | CUle
228  | CUlt
229  | CUge
230  | CUgt
231  deriving (Show, Eq)
232
233data Instr
234  = Add Value Value
235  | Sub Value Value
236  | -- | Div Value Value
237    Mul Value Value
238  | URem Value Value
239  | Rem Value Value
240  | UDiv Value Value
241  | Or Value Value
242  | Xor Value Value
243  | And Value Value
244  | Alloc AllocSize Value
245  | Load LoadType Value
246  | Compare BaseType CmpOp Value Value
247  | Ext SubLongType Value
248  deriving (Show, Eq)
249
250data VolatileInstr
251  = Store ExtType Value Value
252  | Blit Value Value Word64
253  deriving (Show, Eq)
254
255data Statement
256  = Assign LocalIdent BaseType Instr
257  | Call (Maybe (LocalIdent, Abity)) Value [FuncArg]
258  | Volatile VolatileInstr
259  deriving (Show, Eq)
260
261data Phi
262  = Phi
263  { pName :: LocalIdent,
264    pType :: BaseType,
265    pLabels :: Map BlockIdent Value
266  }
267  deriving (Show, Eq)
268
269data Block'
270  = Block'
271  { label' :: BlockIdent,
272    phi' :: [Phi],
273    stmt' :: [Statement],
274    term' :: Maybe JumpInstr
275  }
276  deriving (Show, Eq)
277
278insertJumps :: [Block'] -> Maybe [Block]
279insertJumps xs = foldM go [] $ zipWithNext xs
280  where
281    zipWithNext :: [a] -> [(a, Maybe a)]
282    zipWithNext [] = []
283    zipWithNext lst@(_ : t) = zip lst $ map Just t ++ [Nothing]
284
285    fromBlock' :: Block' -> JumpInstr -> Block
286    fromBlock' (Block' l p s _) = Block l p s
287
288    go :: [Block] -> (Block', Maybe Block') -> Maybe [Block]
289    go acc (x@Block' {term' = Just ji}, _) =
290      Just (acc ++ [fromBlock' x ji])
291    go acc (x@Block' {term' = Nothing}, Just nxt) =
292      Just (acc ++ [fromBlock' x (Jump $ label' nxt)])
293    go _ (Block' {term' = Nothing}, Nothing) =
294      Nothing
295
296data Block
297  = Block
298  { label :: BlockIdent,
299    phi :: [Phi],
300    stmt :: [Statement],
301    term :: JumpInstr
302  }
303  deriving (Show, Eq)