--------------------------------------------------------------------------
-- |
-- Module      :  Harpy.X86Assembler
-- Copyright   :  (c) 2006-2007 Martin Grabmueller and Dirk Kleeblatt
-- License     :  GPL
-- 
-- Maintainer  :  {magr,klee}@cs.tu-berlin.de
-- Stability   :  provisional
-- Portability :  non-portable
--
-- A type class based layer on top of X86CodeGen
-- which determines the addressing modes from the types of the
-- operands.
--------------------------------------------------------------------------
module Harpy.X86Assembler where

import Harpy.X86CodeGen
import Harpy.CodeGenMonad
import Data.Word
import Foreign.Ptr

import qualified Text.PrettyPrint.HughesPJ as PP


-- address modes used in this module:

-- Word8/16/32	   	     immediate values
-- Reg8/16/32	             register
-- Addr Word32		     absolut
-- Ind Reg32		     register indirect
-- (Disp, Reg32)		     register indirect with displacement
-- (Reg32, Reg32, Scale)	     (base, index, scale), effective address is (base + index * scale)
-- (Disp, Reg32, Scale)	     (disp, index, scale), effective address is (disp + index * scale)
-- (Disp, Reg32, Reg32, Scale)  (base, index, scale) + displacement (only ebp is allowed as base register)
-- Label                        not-yet-specified label

onlyEbp = failCodeGen (PP.text "only epb is allowed as base register for disp/base/index/scale addressing")
onlyCl  = failCodeGen (PP.text "only cl is allowed as shift count")


-- x86 Registers

newtype Reg8 = Reg8 Word8
al, cl, dl, bl, ah, ch, dh, bh :: Reg8

al = Reg8 0
cl = Reg8 1
dl = Reg8 2
bl = Reg8 3
ah = Reg8 4
ch = Reg8 5
dh = Reg8 6
bh = Reg8 7

newtype Reg16 = Reg16 Word8
ax, cx, dx, bx, sp, bp, si, di :: Reg16

ax = Reg16 0
cx = Reg16 1
dx = Reg16 2
bx = Reg16 3
sp = Reg16 4
bp = Reg16 5
si = Reg16 6
di = Reg16 7

newtype Reg32 = Reg32 Word8 deriving Eq
eax, ecx, edx, ebx, esp, ebp, esi, edi :: Reg32

eax = Reg32 0
ecx = Reg32 1
edx = Reg32 2
ebx = Reg32 3
esp = Reg32 4
ebp = Reg32 5
esi = Reg32 6
edi = Reg32 7

newtype XMMReg = XMMReg Word8

xmm0 = XMMReg 0
xmm1 = XMMReg 1
xmm2 = XMMReg 2
xmm3 = XMMReg 3
xmm4 = XMMReg 4
xmm5 = XMMReg 5
xmm6 = XMMReg 6
xmm7 = XMMReg 7

-- TODO: instances for other registers

instance Show Reg32 where
 show (Reg32 0) = "eax"
 show (Reg32 1) = "ecx"
 show (Reg32 2) = "edx"
 show (Reg32 3) = "ebx"
 show (Reg32 4) = "esp"
 show (Reg32 5) = "ebp"
 show (Reg32 6) = "esi"
 show (Reg32 7) = "edi"

-- memory addresses

newtype Addr  = Addr Word32
newtype Ind   = Ind Reg32
newtype Disp  = Disp Word32

data    Scale = S1 | S2 | S4 | S8

scaleToShift :: Scale -> Word8
scaleToShift S1 = 0
scaleToShift S2 = 1
scaleToShift S4 = 2
scaleToShift S8 = 3

newtype FPReg = FPReg Word8

data FPTopReg = FPTopReg

fpTop = FPTopReg

fp0 = FPReg 0
fp1 = FPReg 1
fp2 = FPReg 2
fp3 = FPReg 3
fp4 = FPReg 4
fp5 = FPReg 5
fp6 = FPReg 6
fp7 = FPReg 7

-- int 3

breakpoint = ensureBufferSize x86_max_instruction_bytes >> x86_breakpoint


-- clear direction flag

cld = ensureBufferSize x86_max_instruction_bytes >> x86_cld


-- store string

stosb = ensureBufferSize x86_max_instruction_bytes >> x86_stosb
stosl = ensureBufferSize x86_max_instruction_bytes >> x86_stosl
stosd = ensureBufferSize x86_max_instruction_bytes >> x86_stosd


-- move string

movsb = ensureBufferSize x86_max_instruction_bytes >> x86_movsb
movsl = ensureBufferSize x86_max_instruction_bytes >> x86_movsl
--movsd = ensureBufferSize x86_max_instruction_bytes >> x86_movsd


-- read time stamp counter

rdtsc = ensureBufferSize x86_max_instruction_bytes >> x86_rdtsc


-- compare and exchange

class Cmpxchg a b where
  cmpxchg :: a -> b -> CodeGen e s ()

instance Cmpxchg Reg32 Reg32 where
  cmpxchg (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_reg_reg dest source

instance Cmpxchg Addr Reg32 where
  cmpxchg (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_mem_reg dest source

instance Cmpxchg (Disp, Reg32) Reg32 where
  cmpxchg (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_membase_reg dest disp source

instance Cmpxchg Ind Reg32 where
  cmpxchg (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_cmpxchg_membase_reg dest 0 source



-- exchange memory/register with register

class Xchg a b where
  xchg :: a -> b -> CodeGen e s ()

instance Xchg Reg8 Reg8 where
  xchg (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_reg_reg dest source 1

instance Xchg Reg32 Reg32 where
  xchg (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_reg_reg dest source 4

instance Xchg Addr Reg8 where
  xchg (Addr dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_mem_reg dest source 1

instance Xchg Addr Reg32 where
  xchg (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_mem_reg dest source 4

instance Xchg (Disp, Reg32) Reg8 where
  xchg (Disp disp, Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest disp source 1

instance Xchg Ind Reg8 where
  xchg (Ind (Reg32 dest)) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest 0 source 1

instance Xchg (Disp, Reg32) Reg32 where
  xchg (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest disp source 4

instance Xchg Ind Reg32 where
  xchg (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xchg_membase_reg dest 0 source 4


-- exchange and add

class Xadd a b where
  xadd :: a -> b -> CodeGen e s ()

instance Xadd Reg8 Reg8 where
  xadd (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_reg_reg dest source 1

instance Xadd Reg32 Reg32 where
  xadd (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_reg_reg dest source 4

instance Xadd Addr Reg8 where
  xadd (Addr dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_mem_reg dest source 1

instance Xadd Addr Reg32 where
  xadd (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_mem_reg dest source 4

instance Xadd (Disp, Reg32) Reg8 where
  xadd (Disp disp, Reg32 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest disp source 1

instance Xadd Ind Reg8 where
  xadd (Ind (Reg32 dest)) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest 0 source 1

instance Xadd (Disp, Reg32) Reg32 where
  xadd (Disp disp, Reg32 dest) (Reg32 source) =  ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest disp source 4

instance Xadd Ind Reg32 where
  xadd (Ind (Reg32 dest)) (Reg32 source) =  ensureBufferSize x86_max_instruction_bytes >> x86_xadd_membase_reg dest 0 source 4


-- Increment by 1

class Inc a where
  inc :: a -> CodeGen e s ()

instance Inc Addr where
  inc (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_mem dest

instance Inc (Disp, Reg32) where
  inc (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_membase dest disp

instance Inc Ind where
  inc (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_membase dest 0

instance Inc Reg32 where
  inc (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_inc_reg dest


-- Decrement by 1

class Dec a where
  dec :: a -> CodeGen e s ()

instance Dec Addr where
  dec (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_mem dest

instance Dec (Disp, Reg32) where
  dec (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_membase dest disp

instance Dec Ind where
  dec (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_membase dest 0

instance Dec Reg32 where
  dec (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_dec_reg dest


-- One's complement negation

class Not a where
  not :: a -> CodeGen e s ()

instance Not Addr where
  not (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_mem dest

instance Not (Disp, Reg32) where
  not (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_membase dest disp

instance Not Ind where
  not (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_not_membase dest 0

instance Not Reg32 where
  not (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_not_reg dest


-- Two's complement negation

class Neg a where
  neg :: a -> CodeGen e s ()

instance Neg Addr where
  neg (Addr dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_mem dest

instance Neg (Disp, Reg32) where
  neg (Disp disp, Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_membase dest disp

instance Neg Ind where
  neg (Ind (Reg32 dest)) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_membase dest 0

instance Neg Reg32 where
  neg (Reg32 dest) = ensureBufferSize x86_max_instruction_bytes >> x86_neg_reg dest


-- No operation

nop = ensureBufferSize x86_max_instruction_bytes >> x86_nop


-- ALU operations

-- Calling "x86_alu_reg8_reg8 _ _ _ *False* *False*" is a little bit hackish: the last two
-- arguments are set to True for the "high byte registers" ah, bh, ch and dh.
-- x86_reg8_emit then sets the 3rd bit in the register number. This bit is set in our
-- encoding anyway to the right value, so we simply skip this part.

class Add a b where
  add :: a -> b -> CodeGen e s ()

instance Add Reg32 Word32 where
  add (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_add dest (fromIntegral imm)

instance Add Addr Word32 where
  add (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_add dest (fromIntegral imm)

instance Add (Disp, Reg32) Word32 where
  add (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_add dest disp (fromIntegral imm)

instance Add Ind Word32 where
  add (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_add dest 0 (fromIntegral imm)

instance Add (Disp, Reg32) Word8 where
  add (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_add dest disp (fromIntegral imm)

instance Add Ind Word8 where
  add (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_add dest 0 (fromIntegral imm)

instance Add Addr Reg32 where
  add (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_add dest source

instance Add (Disp, Reg32) Reg32 where
  add (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_add dest disp source

instance Add Ind Reg32 where
  add (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_add dest 0 source

instance Add Reg32 Reg32 where
  add (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_add dest source

instance Add Reg8 Reg8 where
  add (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_add dest source False False

instance Add Reg32 Addr where
  add (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_add dest source

instance Add Reg32 (Disp, Reg32) where
  add (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_add dest source disp

instance Add Reg32 Ind where
  add (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_add dest source 0


class Or a b where
  or :: a -> b -> CodeGen e s ()

instance Or Reg32 Word32 where
  or (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_or dest (fromIntegral imm)

instance Or Addr Word32 where
  or (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_or dest (fromIntegral imm)

instance Or (Disp, Reg32) Word32 where
  or (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_or dest disp (fromIntegral imm)

instance Or Ind Word32 where
  or (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_or dest 0 (fromIntegral imm)

instance Or (Disp, Reg32) Word8 where
  or (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_or dest disp (fromIntegral imm)

instance Or Ind Word8 where
  or (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_or dest 0 (fromIntegral imm)

instance Or Addr Reg32 where
  or (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_or dest source

instance Or (Disp, Reg32) Reg32 where
  or (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_or dest disp source

instance Or Ind Reg32 where
  or (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_or dest 0 source

instance Or Reg32 Reg32 where
  or (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_or dest source

instance Or Reg8 Reg8 where
  or (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_or dest source False False

instance Or Reg32 Addr where
  or (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_or dest source

instance Or Reg32 (Disp, Reg32) where
  or (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_or dest source disp

instance Or Reg32 Ind where
  or (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_or dest source 0


class Adc a b where
  adc :: a -> b -> CodeGen e s ()

instance Adc Reg32 Word32 where
  adc (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_adc dest (fromIntegral imm)

instance Adc Addr Word32 where
  adc (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_adc dest (fromIntegral imm)

instance Adc (Disp, Reg32) Word32 where
  adc (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_adc dest disp (fromIntegral imm)

instance Adc Ind Word32 where
  adc (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_adc dest 0 (fromIntegral imm)

instance Adc (Disp, Reg32) Word8 where
  adc (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_adc dest disp (fromIntegral imm)

instance Adc Ind Word8 where
  adc (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_adc dest 0 (fromIntegral imm)

instance Adc Addr Reg32 where
  adc (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_adc dest source

instance Adc (Disp, Reg32) Reg32 where
  adc (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_adc dest disp source

instance Adc Ind Reg32 where
  adc (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_adc dest 0 source

instance Adc Reg32 Reg32 where
  adc (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_adc dest source

instance Adc Reg8 Reg8 where
  adc (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_adc dest source False False

instance Adc Reg32 Addr where
  adc (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_adc dest source

instance Adc Reg32 (Disp, Reg32) where
  adc (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_adc dest source disp

instance Adc Reg32 Ind where
  adc (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_adc dest source 0


class Sbb a b where
  sbb :: a -> b -> CodeGen e s ()

instance Sbb Reg32 Word32 where
  sbb (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_sbb dest (fromIntegral imm)

instance Sbb Addr Word32 where
  sbb (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_sbb dest (fromIntegral imm)

instance Sbb (Disp, Reg32) Word32 where
  sbb (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sbb dest disp (fromIntegral imm)

instance Sbb Ind Word32 where
  sbb (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sbb dest 0 (fromIntegral imm)

instance Sbb (Disp, Reg32) Word8 where
  sbb (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sbb dest disp (fromIntegral imm)

instance Sbb Ind Word8 where
  sbb (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_sbb dest 0 (fromIntegral imm)

instance Sbb Addr Reg32 where
  sbb (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_sbb dest source

instance Sbb (Disp, Reg32) Reg32 where
  sbb (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sbb dest disp source

instance Sbb Ind Reg32 where
  sbb (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_sbb dest 0 source

instance Sbb Reg32 Reg32 where
  sbb (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_sbb dest source

instance Sbb Reg8 Reg8 where
  sbb (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_sbb dest source False False

instance Sbb Reg32 Addr where
  sbb (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_sbb dest source

instance Sbb Reg32 (Disp, Reg32) where
  sbb (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sbb dest source disp

instance Sbb Reg32 Ind where
  sbb (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_sbb dest source 0


class And a b where
  and :: a -> b -> CodeGen e s ()

instance And Reg32 Word32 where
  and (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_and dest (fromIntegral imm)

instance And Addr Word32 where
  and (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_imm x86_and dest (fromIntegral imm)

instance And (Disp, Reg32) Word32 where
  and (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_and dest disp (fromIntegral imm)

instance And Ind Word32 where
  and (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_and dest 0 (fromIntegral imm)

instance And (Disp, Reg32) Word8 where
  and (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_and dest disp (fromIntegral imm)

instance And Ind Word8 where
  and (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm x86_and dest 0 (fromIntegral imm)

instance And Addr Reg32 where
  and (Addr dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_and dest source

instance And (Disp, Reg32) Reg32 where
  and (Disp disp, Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_and dest disp source

instance And Ind Reg32 where
  and (Ind (Reg32 dest)) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_reg x86_and dest 0 source

instance And Reg32 Reg32 where
  and (Reg32 dest) (Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_reg x86_and dest source

instance And Reg8 Reg8 where
  and (Reg8 dest) (Reg8 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg8_reg8 x86_and dest source False False

instance And Reg32 Addr where
  and (Reg32 dest) (Addr source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_mem x86_and dest source

instance And Reg32 (Disp, Reg32) where
  and (Reg32 dest) (Disp disp, Reg32 source) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_and dest source disp

instance And Reg32 Ind where
  and (Reg32 dest) (Ind (Reg32 source)) = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_membase x86_and dest source 0


class Sub a b where
  sub :: a -> b -> CodeGen e s ()

instance Sub Reg32 Word32 where
  sub (Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_reg_imm x86_sub dest (fromIntegral imm)

instance Sub Addr Word32 where
  sub (Addr dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_mem_reg x86_sub dest (fromIntegral imm)

instance Sub (Disp, Reg32) Word32 where
  sub (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sub dest disp (fromIntegral imm)

instance Sub Ind Word32 where
  sub (Ind (Reg32 dest)) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase_imm x86_sub dest 0 (fromIntegral imm)

instance Sub (Disp, Reg32) Word8 where
  sub (Disp disp, Reg32 dest) imm = ensureBufferSize x86_max_instruction_bytes >> x86_alu_membase8_imm