module GHC.CmmToAsm.AArch64.Cond  where

import GHC.Prelude hiding (EQ)

-- https://developer.arm.com/documentation/den0024/a/the-a64-instruction-set/data-processing-instructions/conditional-instructions

-- TODO: This appears to go a bit overboard? Maybe we should stick with what LLVM
-- settled on for fcmp?
-- false: always yields false, regardless of operands.
-- oeq: yields true if both operands are not a QNAN and op1 is equal to op2.
-- ogt: yields true if both operands are not a QNAN and op1 is greater than op2.
-- oge: yields true if both operands are not a QNAN and op1 is greater than or equal to op2.
-- olt: yields true if both operands are not a QNAN and op1 is less than op2.
-- ole: yields true if both operands are not a QNAN and op1 is less than or equal to op2.
-- one: yields true if both operands are not a QNAN and op1 is not equal to op2.
-- ord: yields true if both operands are not a QNAN.
-- ueq: yields true if either operand is a QNAN or op1 is equal to op2.
-- ugt: yields true if either operand is a QNAN or op1 is greater than op2.
-- uge: yields true if either operand is a QNAN or op1 is greater than or equal to op2.
-- ult: yields true if either operand is a QNAN or op1 is less than op2.
-- ule: yields true if either operand is a QNAN or op1 is less than or equal to op2.
-- une: yields true if either operand is a QNAN or op1 is not equal to op2.
-- uno: yields true if either operand is a QNAN.
-- true: always yields true, regardless of operands.
--
-- LLVMs icmp knows about:
-- eq: yields true if the operands are equal, false otherwise. No sign interpretation is necessary or performed.
-- ne: yields true if the operands are unequal, false otherwise. No sign interpretation is necessary or performed.
-- ugt: interprets the operands as unsigned values and yields true if op1 is greater than op2.
-- uge: interprets the operands as unsigned values and yields true if op1 is greater than or equal to op2.
-- ult: interprets the operands as unsigned values and yields true if op1 is less than op2.
-- ule: interprets the operands as unsigned values and yields true if op1 is less than or equal to op2.
-- sgt: interprets the operands as signed values and yields true if op1 is greater than op2.
-- sge: interprets the operands as signed values and yields true if op1 is greater than or equal to op2.
-- slt: interprets the operands as signed values and yields true if op1 is less than op2.
-- sle: interprets the operands as signed values and yields true if op1 is less than or equal to op2.

data Cond
    = ALWAYS -- b.al
    | EQ     -- b.eq
    | NE     -- b.ne
    -- signed
    | SLT    -- b.lt
    | SLE    -- b.le
    | SGE    -- b.ge
    | SGT    -- b.gt
    -- unsigned
    | ULT    -- b.lo
    | ULE    -- b.ls
    | UGE    -- b.hs
    | UGT    -- b.hi
    -- ordered
    | OLT    -- b.mi
    | OLE    -- b.ls
    | OGE    -- b.ge
    | OGT    -- b.gt
    -- unordered
    | UOLT   -- b.lt
    | UOLE   -- b.le
    | UOGE   -- b.pl
    | UOGT   -- b.hi
    -- others
    -- NEVER -- b.nv
             -- I removed never. According to the ARM spec:
             -- >   The Condition code NV exists only to provide a valid disassembly of
             -- >   the 0b1111 encoding, otherwise its behavior is identical to AL.
             -- This can only lead to disaster. Better to not have it than someone
             -- using it assuming it actually means never.

    | VS     -- oVerflow set
    | VC     -- oVerflow clear
    deriving Cond -> Cond -> Bool
(Cond -> Cond -> Bool) -> (Cond -> Cond -> Bool) -> Eq Cond
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Cond -> Cond -> Bool
== :: Cond -> Cond -> Bool
$c/= :: Cond -> Cond -> Bool
/= :: Cond -> Cond -> Bool
Eq