module CmmMachOp
    ( MachOp(..)
    , pprMachOp, isCommutableMachOp, isAssociativeMachOp
    , isComparisonMachOp, maybeIntComparison, machOpResultType
    , machOpArgReps, maybeInvertComparison
    
    , mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot
    , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem
    , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe
    , mo_wordULe, mo_wordUGt, mo_wordULt
    , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot
    , mo_wordShl, mo_wordSShr, mo_wordUShr
    , mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32
    , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord
    , mo_u_32ToWord, mo_s_32ToWord
    , mo_32To8, mo_32To16, mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64
    
    , CallishMachOp(..), callishMachOpHints
    , pprCallishMachOp
    , machOpMemcpyishAlign
    
    , AtomicMachOp(..)
   )
where
#include "HsVersions.h"
import GhcPrelude
import CmmType
import Outputable
import DynFlags
data MachOp
  
  = MO_Add Width
  | MO_Sub Width
  | MO_Eq  Width
  | MO_Ne  Width
  | MO_Mul Width                
  
  | MO_S_MulMayOflo Width       
  | MO_S_Quot Width             
  | MO_S_Rem  Width             
  | MO_S_Neg  Width             
  
  | MO_U_MulMayOflo Width       
  | MO_U_Quot Width             
  | MO_U_Rem  Width             
  
  | MO_S_Ge Width
  | MO_S_Le Width
  | MO_S_Gt Width
  | MO_S_Lt Width
  
  | MO_U_Ge Width
  | MO_U_Le Width
  | MO_U_Gt Width
  | MO_U_Lt Width
  
  | MO_F_Add  Width
  | MO_F_Sub  Width
  | MO_F_Neg  Width             
  | MO_F_Mul  Width
  | MO_F_Quot Width
  
  | MO_F_Eq Width
  | MO_F_Ne Width
  | MO_F_Ge Width
  | MO_F_Le Width
  | MO_F_Gt Width
  | MO_F_Lt Width
  
  
  | MO_And   Width
  | MO_Or    Width
  | MO_Xor   Width
  | MO_Not   Width
  | MO_Shl   Width
  | MO_U_Shr Width      
  | MO_S_Shr Width      
  
  
  | MO_SF_Conv Width Width      
  | MO_FS_Conv Width Width      
  | MO_SS_Conv Width Width      
  | MO_UU_Conv Width Width      
  | MO_FF_Conv Width Width      
  
  | MO_V_Insert  Length Width   
  | MO_V_Extract Length Width   
  
  | MO_V_Add Length Width
  | MO_V_Sub Length Width
  | MO_V_Mul Length Width
  
  | MO_VS_Quot Length Width
  | MO_VS_Rem  Length Width
  | MO_VS_Neg  Length Width
  
  | MO_VU_Quot Length Width
  | MO_VU_Rem  Length Width
  
  | MO_VF_Insert  Length Width   
  | MO_VF_Extract Length Width   
  
  | MO_VF_Add  Length Width
  | MO_VF_Sub  Length Width
  | MO_VF_Neg  Length Width      
  | MO_VF_Mul  Length Width
  | MO_VF_Quot Length Width
  
  | MO_AlignmentCheck Int Width
  deriving (Eq, Show)
pprMachOp :: MachOp -> SDoc
pprMachOp mo = text (show mo)
mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot
    , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem
    , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe
    , mo_wordULe, mo_wordUGt, mo_wordULt
    , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot, mo_wordShl, mo_wordSShr, mo_wordUShr
    , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord, mo_u_32ToWord, mo_s_32ToWord
    , mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64
    :: DynFlags -> MachOp
mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32
    , mo_32To8, mo_32To16
    :: MachOp
mo_wordAdd      dflags = MO_Add (wordWidth dflags)
mo_wordSub      dflags = MO_Sub (wordWidth dflags)
mo_wordEq       dflags = MO_Eq  (wordWidth dflags)
mo_wordNe       dflags = MO_Ne  (wordWidth dflags)
mo_wordMul      dflags = MO_Mul (wordWidth dflags)
mo_wordSQuot    dflags = MO_S_Quot (wordWidth dflags)
mo_wordSRem     dflags = MO_S_Rem (wordWidth dflags)
mo_wordSNeg     dflags = MO_S_Neg (wordWidth dflags)
mo_wordUQuot    dflags = MO_U_Quot (wordWidth dflags)
mo_wordURem     dflags = MO_U_Rem (wordWidth dflags)
mo_wordSGe      dflags = MO_S_Ge  (wordWidth dflags)
mo_wordSLe      dflags = MO_S_Le  (wordWidth dflags)
mo_wordSGt      dflags = MO_S_Gt  (wordWidth dflags)
mo_wordSLt      dflags = MO_S_Lt  (wordWidth dflags)
mo_wordUGe      dflags = MO_U_Ge  (wordWidth dflags)
mo_wordULe      dflags = MO_U_Le  (wordWidth dflags)
mo_wordUGt      dflags = MO_U_Gt  (wordWidth dflags)
mo_wordULt      dflags = MO_U_Lt  (wordWidth dflags)
mo_wordAnd      dflags = MO_And (wordWidth dflags)
mo_wordOr       dflags = MO_Or  (wordWidth dflags)
mo_wordXor      dflags = MO_Xor (wordWidth dflags)
mo_wordNot      dflags = MO_Not (wordWidth dflags)
mo_wordShl      dflags = MO_Shl (wordWidth dflags)
mo_wordSShr     dflags = MO_S_Shr (wordWidth dflags)
mo_wordUShr     dflags = MO_U_Shr (wordWidth dflags)
mo_u_8To32             = MO_UU_Conv W8 W32
mo_s_8To32             = MO_SS_Conv W8 W32
mo_u_16To32            = MO_UU_Conv W16 W32
mo_s_16To32            = MO_SS_Conv W16 W32
mo_u_8ToWord    dflags = MO_UU_Conv W8  (wordWidth dflags)
mo_s_8ToWord    dflags = MO_SS_Conv W8  (wordWidth dflags)
mo_u_16ToWord   dflags = MO_UU_Conv W16 (wordWidth dflags)
mo_s_16ToWord   dflags = MO_SS_Conv W16 (wordWidth dflags)
mo_s_32ToWord   dflags = MO_SS_Conv W32 (wordWidth dflags)
mo_u_32ToWord   dflags = MO_UU_Conv W32 (wordWidth dflags)
mo_WordTo8      dflags = MO_UU_Conv (wordWidth dflags) W8
mo_WordTo16     dflags = MO_UU_Conv (wordWidth dflags) W16
mo_WordTo32     dflags = MO_UU_Conv (wordWidth dflags) W32
mo_WordTo64     dflags = MO_UU_Conv (wordWidth dflags) W64
mo_32To8               = MO_UU_Conv W32 W8
mo_32To16              = MO_UU_Conv W32 W16
isCommutableMachOp :: MachOp -> Bool
isCommutableMachOp mop =
  case mop of
        MO_Add _                -> True
        MO_Eq _                 -> True
        MO_Ne _                 -> True
        MO_Mul _                -> True
        MO_S_MulMayOflo _       -> True
        MO_U_MulMayOflo _       -> True
        MO_And _                -> True
        MO_Or _                 -> True
        MO_Xor _                -> True
        MO_F_Add _              -> True
        MO_F_Mul _              -> True
        _other                  -> False
isAssociativeMachOp :: MachOp -> Bool
isAssociativeMachOp mop =
  case mop of
        MO_Add {} -> True       
        MO_Mul {} -> True 
        MO_And {} -> True
        MO_Or  {} -> True
        MO_Xor {} -> True
        _other    -> False
isComparisonMachOp :: MachOp -> Bool
isComparisonMachOp mop =
  case mop of
    MO_Eq   _  -> True
    MO_Ne   _  -> True
    MO_S_Ge _  -> True
    MO_S_Le _  -> True
    MO_S_Gt _  -> True
    MO_S_Lt _  -> True
    MO_U_Ge _  -> True
    MO_U_Le _  -> True
    MO_U_Gt _  -> True
    MO_U_Lt _  -> True
    MO_F_Eq {} -> True
    MO_F_Ne {} -> True
    MO_F_Ge {} -> True
    MO_F_Le {} -> True
    MO_F_Gt {} -> True
    MO_F_Lt {} -> True
    _other     -> False
maybeIntComparison :: MachOp -> Maybe Width
maybeIntComparison mop =
  case mop of
    MO_Eq   w  -> Just w
    MO_Ne   w  -> Just w
    MO_S_Ge w  -> Just w
    MO_S_Le w  -> Just w
    MO_S_Gt w  -> Just w
    MO_S_Lt w  -> Just w
    MO_U_Ge w  -> Just w
    MO_U_Le w  -> Just w
    MO_U_Gt w  -> Just w
    MO_U_Lt w  -> Just w
    _ -> Nothing
maybeInvertComparison :: MachOp -> Maybe MachOp
maybeInvertComparison op
  = case op of  
        MO_Eq r   -> Just (MO_Ne r)
        MO_Ne r   -> Just (MO_Eq r)
        MO_U_Lt r -> Just (MO_U_Ge r)
        MO_U_Gt r -> Just (MO_U_Le r)
        MO_U_Le r -> Just (MO_U_Gt r)
        MO_U_Ge r -> Just (MO_U_Lt r)
        MO_S_Lt r -> Just (MO_S_Ge r)
        MO_S_Gt r -> Just (MO_S_Le r)
        MO_S_Le r -> Just (MO_S_Gt r)
        MO_S_Ge r -> Just (MO_S_Lt r)
        _other    -> Nothing
machOpResultType :: DynFlags -> MachOp -> [CmmType] -> CmmType
machOpResultType dflags mop tys =
  case mop of
    MO_Add {}           -> ty1  
    MO_Sub {}           -> ty1  
    MO_Mul    r         -> cmmBits r
    MO_S_MulMayOflo r   -> cmmBits r
    MO_S_Quot r         -> cmmBits r
    MO_S_Rem  r         -> cmmBits r
    MO_S_Neg  r         -> cmmBits r
    MO_U_MulMayOflo r   -> cmmBits r
    MO_U_Quot r         -> cmmBits r
    MO_U_Rem  r         -> cmmBits r
    MO_Eq {}            -> comparisonResultRep dflags
    MO_Ne {}            -> comparisonResultRep dflags
    MO_S_Ge {}          -> comparisonResultRep dflags
    MO_S_Le {}          -> comparisonResultRep dflags
    MO_S_Gt {}          -> comparisonResultRep dflags
    MO_S_Lt {}          -> comparisonResultRep dflags
    MO_U_Ge {}          -> comparisonResultRep dflags
    MO_U_Le {}          -> comparisonResultRep dflags
    MO_U_Gt {}          -> comparisonResultRep dflags
    MO_U_Lt {}          -> comparisonResultRep dflags
    MO_F_Add r          -> cmmFloat r
    MO_F_Sub r          -> cmmFloat r
    MO_F_Mul r          -> cmmFloat r
    MO_F_Quot r         -> cmmFloat r
    MO_F_Neg r          -> cmmFloat r
    MO_F_Eq  {}         -> comparisonResultRep dflags
    MO_F_Ne  {}         -> comparisonResultRep dflags
    MO_F_Ge  {}         -> comparisonResultRep dflags
    MO_F_Le  {}         -> comparisonResultRep dflags
    MO_F_Gt  {}         -> comparisonResultRep dflags
    MO_F_Lt  {}         -> comparisonResultRep dflags
    MO_And {}           -> ty1  
    MO_Or {}            -> ty1
    MO_Xor {}           -> ty1
    MO_Not   r          -> cmmBits r
    MO_Shl   r          -> cmmBits r
    MO_U_Shr r          -> cmmBits r
    MO_S_Shr r          -> cmmBits r
    MO_SS_Conv _ to     -> cmmBits to
    MO_UU_Conv _ to     -> cmmBits to
    MO_FS_Conv _ to     -> cmmBits to
    MO_SF_Conv _ to     -> cmmFloat to
    MO_FF_Conv _ to     -> cmmFloat to
    MO_V_Insert  l w    -> cmmVec l (cmmBits w)
    MO_V_Extract _ w    -> cmmBits w
    MO_V_Add l w        -> cmmVec l (cmmBits w)
    MO_V_Sub l w        -> cmmVec l (cmmBits w)
    MO_V_Mul l w        -> cmmVec l (cmmBits w)
    MO_VS_Quot l w      -> cmmVec l (cmmBits w)
    MO_VS_Rem  l w      -> cmmVec l (cmmBits w)
    MO_VS_Neg  l w      -> cmmVec l (cmmBits w)
    MO_VU_Quot l w      -> cmmVec l (cmmBits w)
    MO_VU_Rem  l w      -> cmmVec l (cmmBits w)
    MO_VF_Insert  l w   -> cmmVec l (cmmFloat w)
    MO_VF_Extract _ w   -> cmmFloat w
    MO_VF_Add  l w      -> cmmVec l (cmmFloat w)
    MO_VF_Sub  l w      -> cmmVec l (cmmFloat w)
    MO_VF_Mul  l w      -> cmmVec l (cmmFloat w)
    MO_VF_Quot l w      -> cmmVec l (cmmFloat w)
    MO_VF_Neg  l w      -> cmmVec l (cmmFloat w)
    MO_AlignmentCheck _ _ -> ty1
  where
    (ty1:_) = tys
comparisonResultRep :: DynFlags -> CmmType
comparisonResultRep = bWord  
machOpArgReps :: DynFlags -> MachOp -> [Width]
machOpArgReps dflags op =
  case op of
    MO_Add    r         -> [r,r]
    MO_Sub    r         -> [r,r]
    MO_Eq     r         -> [r,r]
    MO_Ne     r         -> [r,r]
    MO_Mul    r         -> [r,r]
    MO_S_MulMayOflo r   -> [r,r]
    MO_S_Quot r         -> [r,r]
    MO_S_Rem  r         -> [r,r]
    MO_S_Neg  r         -> [r]
    MO_U_MulMayOflo r   -> [r,r]
    MO_U_Quot r         -> [r,r]
    MO_U_Rem  r         -> [r,r]
    MO_S_Ge r           -> [r,r]
    MO_S_Le r           -> [r,r]
    MO_S_Gt r           -> [r,r]
    MO_S_Lt r           -> [r,r]
    MO_U_Ge r           -> [r,r]
    MO_U_Le r           -> [r,r]
    MO_U_Gt r           -> [r,r]
    MO_U_Lt r           -> [r,r]
    MO_F_Add r          -> [r,r]
    MO_F_Sub r          -> [r,r]
    MO_F_Mul r          -> [r,r]
    MO_F_Quot r         -> [r,r]
    MO_F_Neg r          -> [r]
    MO_F_Eq  r          -> [r,r]
    MO_F_Ne  r          -> [r,r]
    MO_F_Ge  r          -> [r,r]
    MO_F_Le  r          -> [r,r]
    MO_F_Gt  r          -> [r,r]
    MO_F_Lt  r          -> [r,r]
    MO_And   r          -> [r,r]
    MO_Or    r          -> [r,r]
    MO_Xor   r          -> [r,r]
    MO_Not   r          -> [r]
    MO_Shl   r          -> [r, wordWidth dflags]
    MO_U_Shr r          -> [r, wordWidth dflags]
    MO_S_Shr r          -> [r, wordWidth dflags]
    MO_SS_Conv from _   -> [from]
    MO_UU_Conv from _   -> [from]
    MO_SF_Conv from _   -> [from]
    MO_FS_Conv from _   -> [from]
    MO_FF_Conv from _   -> [from]
    MO_V_Insert  l r    -> [typeWidth (vec l (cmmBits r)),r,wordWidth dflags]
    MO_V_Extract l r    -> [typeWidth (vec l (cmmBits r)),wordWidth dflags]
    MO_V_Add _ r        -> [r,r]
    MO_V_Sub _ r        -> [r,r]
    MO_V_Mul _ r        -> [r,r]
    MO_VS_Quot _ r      -> [r,r]
    MO_VS_Rem  _ r      -> [r,r]
    MO_VS_Neg  _ r      -> [r]
    MO_VU_Quot _ r      -> [r,r]
    MO_VU_Rem  _ r      -> [r,r]
    MO_VF_Insert  l r   -> [typeWidth (vec l (cmmFloat r)),r,wordWidth dflags]
    MO_VF_Extract l r   -> [typeWidth (vec l (cmmFloat r)),wordWidth dflags]
    MO_VF_Add  _ r      -> [r,r]
    MO_VF_Sub  _ r      -> [r,r]
    MO_VF_Mul  _ r      -> [r,r]
    MO_VF_Quot _ r      -> [r,r]
    MO_VF_Neg  _ r      -> [r]
    MO_AlignmentCheck _ r -> [r]
data CallishMachOp
  = MO_F64_Pwr
  | MO_F64_Sin
  | MO_F64_Cos
  | MO_F64_Tan
  | MO_F64_Sinh
  | MO_F64_Cosh
  | MO_F64_Tanh
  | MO_F64_Asin
  | MO_F64_Acos
  | MO_F64_Atan
  | MO_F64_Log
  | MO_F64_Exp
  | MO_F64_Fabs
  | MO_F64_Sqrt
  | MO_F32_Pwr
  | MO_F32_Sin
  | MO_F32_Cos
  | MO_F32_Tan
  | MO_F32_Sinh
  | MO_F32_Cosh
  | MO_F32_Tanh
  | MO_F32_Asin
  | MO_F32_Acos
  | MO_F32_Atan
  | MO_F32_Log
  | MO_F32_Exp
  | MO_F32_Fabs
  | MO_F32_Sqrt
  | MO_UF_Conv Width
  | MO_S_QuotRem Width
  | MO_U_QuotRem Width
  | MO_U_QuotRem2 Width
  | MO_Add2      Width
  | MO_SubWordC  Width
  | MO_AddIntC   Width
  | MO_SubIntC   Width
  | MO_U_Mul2    Width
  | MO_WriteBarrier
  | MO_Touch         
  
  | MO_Prefetch_Data Int 
                     
                     
                     
                     
                     
                     
  
  
  
  | MO_Memcpy Int
  | MO_Memset Int
  | MO_Memmove Int
  | MO_Memcmp Int
  | MO_PopCnt Width
  | MO_Pdep Width
  | MO_Pext Width
  | MO_Clz Width
  | MO_Ctz Width
  | MO_BSwap Width
  
  | MO_AtomicRMW Width AtomicMachOp
  | MO_AtomicRead Width
  | MO_AtomicWrite Width
  | MO_Cmpxchg Width
  deriving (Eq, Show)
data AtomicMachOp =
      AMO_Add
    | AMO_Sub
    | AMO_And
    | AMO_Nand
    | AMO_Or
    | AMO_Xor
      deriving (Eq, Show)
pprCallishMachOp :: CallishMachOp -> SDoc
pprCallishMachOp mo = text (show mo)
callishMachOpHints :: CallishMachOp -> ([ForeignHint], [ForeignHint])
callishMachOpHints op = case op of
  MO_Memcpy _  -> ([], [AddrHint,AddrHint,NoHint])
  MO_Memset _  -> ([], [AddrHint,NoHint,NoHint])
  MO_Memmove _ -> ([], [AddrHint,AddrHint,NoHint])
  MO_Memcmp _  -> ([], [AddrHint, AddrHint, NoHint])
  _            -> ([],[])
  
machOpMemcpyishAlign :: CallishMachOp -> Maybe Int
machOpMemcpyishAlign op = case op of
  MO_Memcpy  align -> Just align
  MO_Memset  align -> Just align
  MO_Memmove align -> Just align
  MO_Memcmp  align -> Just align
  _                -> Nothing