1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45-- | This module provides a generic expression language used to describe6-- arithmetic and logic operations on instruction operands in the abstract7-- 'Language.QBE.Simulator' description of QBE semantics. Therefore, in8-- addition to the 'Language.QBE.Simulator.State.Simulator' monad, it is the9-- central component for the abstract description of QBE's semantics.10module Language.QBE.Simulator.Expression11 ( -- * Expression Abstraction12 ValueRepr (..),1314 -- * Conversion Functions,15 fromString,16 toString,17 boolToValue,1819 -- * Comparision20 compareIntExpr,21 compareFloatExpr,22 )23where2425import Data.Char qualified as C26import Data.Word (Word64)27import Language.QBE.Types qualified as QBE2829-- | Generic expression abstraction operating on values of type 'QBE.ExtType'.30-- Values are either fixed-size bitvectors (8-, 16, 32-, or 64-bit) or31-- single-precision or double-precision floating point values. The value type32-- must be tracked internally by the 'ValueRepr' instance. Operations on the33-- value must return 'Nothing' if the operation is performed on values of34-- different types.35class ValueRepr v where36 -- | Create a 'ValueRepr' from an integer literal.37 --38 -- TODO: rename fromLit to fromInt39 fromLit :: QBE.ExtType -> Word64 -> v4041 fromFloat :: Float -> v42 fromDouble :: Double -> v43 toWord64 :: v -> Word6444 getType :: v -> QBE.ExtType4546 floatToInt :: QBE.ExtType -> Bool -> v -> Maybe v47 intToFloat :: QBE.ExtType -> Bool -> v -> Maybe v48 extendFloat :: v -> Maybe v49 truncFloat :: v -> Maybe v5051 -- | Extend a value to the given 'QBE.ExtType'. The 'Bool' is true if52 -- the value should be sign-extended, otherwise it is zero-extended.53 -- If the @v@ is a float or if the current size exceeds (or is equal to)54 -- the size of 'QBE.ExtType', then 'Nothing' is returned.55 extend :: QBE.ExtType -> Bool -> v -> Maybe v5657 -- | Extract the least significant bits of a @v@. The bits to extract58 -- are deduced from the given 'QBE.ExtType'. Returns 'Nothing' if the59 -- 'QBE.ExtType' is a float type, if the value is a float, or if the size60 -- of 'QBE.ExtType' exceeds the size of @v@.61 extract :: QBE.ExtType -> v -> Maybe v6263 -- | Addition.64 add :: v -> v -> Maybe v6566 -- | Subtraction.67 sub :: v -> v -> Maybe v6869 -- | Multiplication.70 mul :: v -> v -> Maybe v7172 -- | Unsigned division.73 div :: v -> v -> Maybe v7475 -- | Unsigned remainder.76 urem :: v -> v -> Maybe v7778 -- | Signed remainder.79 srem :: v -> v -> Maybe v8081 -- | Unsigned division.82 udiv :: v -> v -> Maybe v8384 -- | Bitwise or.85 or :: v -> v -> Maybe v8687 -- | Bitwise xor.88 xor :: v -> v -> Maybe v8990 -- | Bitwise and.91 and :: v -> v -> Maybe v9293 -- | Unary negation.94 neg :: v -> Maybe v9596 -- | Arithmetic right shift, preserving the sign bit of the shifted value.97 -- Shift amount must always be a 32-bit value, the shifted value must be 32- or 64-bit.98 sar :: v -> v -> Maybe v99100 -- | Logical shift right, filling the newly freed bits with zeroes.101 -- Shift amount must always be a 32-bit value, the shifted value must be 32- or 64-bit.102 shr :: v -> v -> Maybe v103104 -- | Logical shift left, always fills the freed bits with zeroes.105 -- Shift amount must always be a 32-bit value, the shifted value must be 32- or 64-bit.106 shl :: v -> v -> Maybe v107108 -- | Check for equality.109 eq :: v -> v -> Maybe v110111 -- | Check if two values are not equal.112 ne :: v -> v -> Maybe v113114 -- | Signed less than or equal to.115 sle :: v -> v -> Maybe v116117 -- | Signed less than.118 slt :: v -> v -> Maybe v119120 -- | Signed greater than or equal to.121 sge :: v -> v -> Maybe v122123 -- | Signed greater than.124 sgt :: v -> v -> Maybe v125126 -- | Unsigned less than or equal to.127 ule :: v -> v -> Maybe v128129 -- | Unsigned less than.130 ult :: v -> v -> Maybe v131132 -- | Unsigned greater than or equal to.133 uge :: v -> v -> Maybe v134135 -- | Unsigned greater then.136 ugt :: v -> v -> Maybe v137138 -- | Ordered, no operand is a NaN.139 -- Only defined for floating points, must return 'Nothing' otherwise.140 ord :: v -> v -> Maybe v141142 -- | Unordered, at least one operand is a NaN.143 -- Only defined for floating points, must return 'Nothing' otherwise.144 unord :: v -> v -> Maybe v145 unord lhs rhs = ord lhs rhs >>= neg146147-- | Convert a string to a list of 8-bit values represented through 'ValueRepr'.148fromString :: (ValueRepr v) => String -> [v]149fromString = map (\c -> fromLit QBE.Byte (fromIntegral $ C.ord c))150151-- | Inverse of 'fromString'.152toString :: (ValueRepr v) => [v] -> String153toString = map (\b -> C.chr (fromIntegral $ toWord64 b))154155-- | Convert a Boolean value to a 64-bit value in 'ValueRepr'.156boolToValue :: (ValueRepr v) => Bool -> v157boolToValue True = fromLit (QBE.Base QBE.Long) 1158boolToValue False = fromLit (QBE.Base QBE.Long) 0159160-- | Map a 'QBE.IntCmpOp' to the corresponding function from 'ValueRepr'.161compareIntExpr :: (ValueRepr v) => QBE.IntCmpOp -> (v -> v -> Maybe v)162compareIntExpr QBE.IEq = eq163compareIntExpr QBE.INe = ne164compareIntExpr QBE.ISle = sle165compareIntExpr QBE.ISlt = slt166compareIntExpr QBE.ISge = sge167compareIntExpr QBE.ISgt = sgt168compareIntExpr QBE.IUle = ule169compareIntExpr QBE.IUlt = ult170compareIntExpr QBE.IUge = uge171compareIntExpr QBE.IUgt = ugt172{-# INLINE compareIntExpr #-}173174-- | Map a 'QBE.FloatCmpOp' to the corresponding function from 'ValueRepr'.175compareFloatExpr :: (ValueRepr v) => QBE.FloatCmpOp -> (v -> v -> Maybe v)176compareFloatExpr QBE.FEq = eq177compareFloatExpr QBE.FNe = ne178compareFloatExpr QBE.FLe = sle179compareFloatExpr QBE.FLt = slt180compareFloatExpr QBE.FGe = sge181compareFloatExpr QBE.FGt = sgt182compareFloatExpr QBE.FOrd = ord183compareFloatExpr QBE.FUnord = unord184{-# INLINE compareFloatExpr #-}