packages feed

x86-64bit 0.1.4 → 0.2

raw patch · 11 files changed

+698/−319 lines, 11 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- CodeGen.X86: [Add, Or, Adc, Sbb, And, Sub, Xor, Cmp, Test, Mov] :: IsSize s => Operand s RW -> Operand s r -> Code
- CodeGen.X86: [Align] :: Size -> Code
- CodeGen.X86: [AppendCode] :: Code -> Code -> Code
- CodeGen.X86: [Call] :: Operand S64 RW -> Code
- CodeGen.X86: [Data] :: Bytes -> Code
- CodeGen.X86: [EmptyCode] :: Code
- CodeGen.X86: [Inc, Dec, Not, Neg] :: IsSize s => Operand s RW -> Code
- CodeGen.X86: [J] :: Maybe Size -> Condition -> Code
- CodeGen.X86: [Jmp] :: Code
- CodeGen.X86: [Jmpq] :: Operand S64 RW -> Code
- CodeGen.X86: [Label] :: Code
- CodeGen.X86: [Lea] :: (IsSize s, IsSize s') => Operand s RW -> Operand s' RW -> Code
- CodeGen.X86: [Pop] :: Operand S64 RW -> Code
- CodeGen.X86: [Push] :: Operand S64 r -> Code
- CodeGen.X86: [Ret, Nop, PushF, PopF, Cmc, Clc, Stc, Cli, Sti, Cld, Std] :: Code
- CodeGen.X86: [Rol, Ror, Rcl, Rcr, Shl, Shr, Sar] :: IsSize s => Operand s RW -> Operand S8 r -> Code
- CodeGen.X86: [Xchg] :: IsSize s => Operand s RW -> Operand s RW -> Code
- CodeGen.X86: base :: Operand s RW -> Addr s
- CodeGen.X86: disp :: Int32 -> Addr s
- CodeGen.X86: imm :: Integral a => a -> Operand s R
- CodeGen.X86: index1 :: Operand s RW -> Addr s
- CodeGen.X86: index2 :: Operand s RW -> Addr s
- CodeGen.X86: index4 :: Operand s RW -> Addr s
- CodeGen.X86: index8 :: Operand s RW -> Addr s
+ CodeGen.X86: S128 :: Size
+ CodeGen.X86: addr16 :: IsSize s => Address s -> Operand rw S16
+ CodeGen.X86: addr32 :: IsSize s => Address s -> Operand rw S32
+ CodeGen.X86: addr64 :: IsSize s => Address s -> Operand rw S64
+ CodeGen.X86: addr8 :: IsSize s => Address s -> Operand rw S8
+ CodeGen.X86: j32 :: Condition -> Code -> Code
+ CodeGen.X86: j8 :: Condition -> Code -> Code
+ CodeGen.X86: j_back32 :: Code -> Condition -> Code
+ CodeGen.X86: j_back8 :: Code -> Condition -> Code
+ CodeGen.X86: jmp :: Code -> Code
+ CodeGen.X86: jmp32 :: Code
+ CodeGen.X86: jmp8 :: Code
+ CodeGen.X86: jmp_back :: Code
+ CodeGen.X86: xmm0 :: FromReg c => c S128
+ CodeGen.X86: xmm1 :: FromReg c => c S128
+ CodeGen.X86: xmm2 :: FromReg c => c S128
+ CodeGen.X86: xmm3 :: FromReg c => c S128
+ CodeGen.X86: xmm4 :: FromReg c => c S128
+ CodeGen.X86: xmm5 :: FromReg c => c S128
+ CodeGen.X86: xmm6 :: FromReg c => c S128
+ CodeGen.X86: xmm7 :: FromReg c => c S128
- CodeGen.X86: addr :: IsSize s' => Addr s' -> Operand s rw
+ CodeGen.X86: addr :: IsSize s => Address s -> Operand rw s'
- CodeGen.X86: ah :: Operand S8 rw
+ CodeGen.X86: ah :: FromReg c => c S8
- CodeGen.X86: al :: Operand S8 rw
+ CodeGen.X86: al :: FromReg c => c S8
- CodeGen.X86: arg1 :: Operand S64 rw
+ CodeGen.X86: arg1 :: FromReg c => c S64
- CodeGen.X86: arg2 :: Operand S64 rw
+ CodeGen.X86: arg2 :: FromReg c => c S64
- CodeGen.X86: arg3 :: Operand S64 rw
+ CodeGen.X86: arg3 :: FromReg c => c S64
- CodeGen.X86: arg4 :: Operand S64 rw
+ CodeGen.X86: arg4 :: FromReg c => c S64
- CodeGen.X86: ax :: Operand S16 rw
+ CodeGen.X86: ax :: FromReg c => c S16
- CodeGen.X86: bh :: Operand S8 rw
+ CodeGen.X86: bh :: FromReg c => c S8
- CodeGen.X86: bl :: Operand S8 rw
+ CodeGen.X86: bl :: FromReg c => c S8
- CodeGen.X86: bp :: Operand S16 rw
+ CodeGen.X86: bp :: FromReg c => c S16
- CodeGen.X86: bpl :: Operand S8 rw
+ CodeGen.X86: bpl :: FromReg c => c S8
- CodeGen.X86: bx :: Operand S16 rw
+ CodeGen.X86: bx :: FromReg c => c S16
- CodeGen.X86: callFun :: Operand S64 RW -> FunPtr a -> Code
+ CodeGen.X86: callFun :: Operand RW S64 -> FunPtr a -> Code
- CodeGen.X86: ch :: Operand S8 rw
+ CodeGen.X86: ch :: FromReg c => c S8
- CodeGen.X86: cl :: Operand S8 rw
+ CodeGen.X86: cl :: FromReg c => c S8
- CodeGen.X86: cx :: Operand S16 rw
+ CodeGen.X86: cx :: FromReg c => c S16
- CodeGen.X86: data Operand :: Size -> Access -> *
+ CodeGen.X86: data Operand :: Access -> Size -> *
- CodeGen.X86: dh :: Operand S8 rw
+ CodeGen.X86: dh :: FromReg c => c S8
- CodeGen.X86: di :: Operand S16 rw
+ CodeGen.X86: di :: FromReg c => c S16
- CodeGen.X86: dil :: Operand S8 rw
+ CodeGen.X86: dil :: FromReg c => c S8
- CodeGen.X86: dl :: Operand S8 rw
+ CodeGen.X86: dl :: FromReg c => c S8
- CodeGen.X86: dx :: Operand S16 rw
+ CodeGen.X86: dx :: FromReg c => c S16
- CodeGen.X86: eax :: Operand S32 rw
+ CodeGen.X86: eax :: FromReg c => c S32
- CodeGen.X86: ebp :: Operand S32 rw
+ CodeGen.X86: ebp :: FromReg c => c S32
- CodeGen.X86: ebx :: Operand S32 rw
+ CodeGen.X86: ebx :: FromReg c => c S32
- CodeGen.X86: ecx :: Operand S32 rw
+ CodeGen.X86: ecx :: FromReg c => c S32
- CodeGen.X86: edi :: Operand S32 rw
+ CodeGen.X86: edi :: FromReg c => c S32
- CodeGen.X86: edx :: Operand S32 rw
+ CodeGen.X86: edx :: FromReg c => c S32
- CodeGen.X86: esi :: Operand S32 rw
+ CodeGen.X86: esi :: FromReg c => c S32
- CodeGen.X86: esp :: Operand S32 rw
+ CodeGen.X86: esp :: FromReg c => c S32
- CodeGen.X86: ipBase :: Operand s rw
+ CodeGen.X86: ipBase :: Operand rw s
- CodeGen.X86: lea8 :: IsSize s => Operand s RW -> Operand S8 RW -> Code
+ CodeGen.X86: lea8 :: IsSize s => Operand RW s -> Operand RW S8 -> Code
- CodeGen.X86: leaData :: (HasBytes a, IsSize s) => Operand s RW -> a -> Code
+ CodeGen.X86: leaData :: (HasBytes t, IsSize s) => Operand RW s -> t -> Code
- CodeGen.X86: r10 :: Operand S64 rw
+ CodeGen.X86: r10 :: FromReg c => c S64
- CodeGen.X86: r10b :: Operand S8 rw
+ CodeGen.X86: r10b :: FromReg c => c S8
- CodeGen.X86: r10d :: Operand S32 rw
+ CodeGen.X86: r10d :: FromReg c => c S32
- CodeGen.X86: r10w :: Operand S16 rw
+ CodeGen.X86: r10w :: FromReg c => c S16
- CodeGen.X86: r11 :: Operand S64 rw
+ CodeGen.X86: r11 :: FromReg c => c S64
- CodeGen.X86: r11b :: Operand S8 rw
+ CodeGen.X86: r11b :: FromReg c => c S8
- CodeGen.X86: r11d :: Operand S32 rw
+ CodeGen.X86: r11d :: FromReg c => c S32
- CodeGen.X86: r11w :: Operand S16 rw
+ CodeGen.X86: r11w :: FromReg c => c S16
- CodeGen.X86: r12 :: Operand S64 rw
+ CodeGen.X86: r12 :: FromReg c => c S64
- CodeGen.X86: r12b :: Operand S8 rw
+ CodeGen.X86: r12b :: FromReg c => c S8
- CodeGen.X86: r12d :: Operand S32 rw
+ CodeGen.X86: r12d :: FromReg c => c S32
- CodeGen.X86: r12w :: Operand S16 rw
+ CodeGen.X86: r12w :: FromReg c => c S16
- CodeGen.X86: r13 :: Operand S64 rw
+ CodeGen.X86: r13 :: FromReg c => c S64
- CodeGen.X86: r13b :: Operand S8 rw
+ CodeGen.X86: r13b :: FromReg c => c S8
- CodeGen.X86: r13d :: Operand S32 rw
+ CodeGen.X86: r13d :: FromReg c => c S32
- CodeGen.X86: r13w :: Operand S16 rw
+ CodeGen.X86: r13w :: FromReg c => c S16
- CodeGen.X86: r14 :: Operand S64 rw
+ CodeGen.X86: r14 :: FromReg c => c S64
- CodeGen.X86: r14b :: Operand S8 rw
+ CodeGen.X86: r14b :: FromReg c => c S8
- CodeGen.X86: r14d :: Operand S32 rw
+ CodeGen.X86: r14d :: FromReg c => c S32
- CodeGen.X86: r14w :: Operand S16 rw
+ CodeGen.X86: r14w :: FromReg c => c S16
- CodeGen.X86: r15 :: Operand S64 rw
+ CodeGen.X86: r15 :: FromReg c => c S64
- CodeGen.X86: r15b :: Operand S8 rw
+ CodeGen.X86: r15b :: FromReg c => c S8
- CodeGen.X86: r15d :: Operand S32 rw
+ CodeGen.X86: r15d :: FromReg c => c S32
- CodeGen.X86: r15w :: Operand S16 rw
+ CodeGen.X86: r15w :: FromReg c => c S16
- CodeGen.X86: r8 :: Operand S64 rw
+ CodeGen.X86: r8 :: FromReg c => c S64
- CodeGen.X86: r8b :: Operand S8 rw
+ CodeGen.X86: r8b :: FromReg c => c S8
- CodeGen.X86: r8d :: Operand S32 rw
+ CodeGen.X86: r8d :: FromReg c => c S32
- CodeGen.X86: r8w :: Operand S16 rw
+ CodeGen.X86: r8w :: FromReg c => c S16
- CodeGen.X86: r9 :: Operand S64 rw
+ CodeGen.X86: r9 :: FromReg c => c S64
- CodeGen.X86: r9b :: Operand S8 rw
+ CodeGen.X86: r9b :: FromReg c => c S8
- CodeGen.X86: r9d :: Operand S32 rw
+ CodeGen.X86: r9d :: FromReg c => c S32
- CodeGen.X86: r9w :: Operand S16 rw
+ CodeGen.X86: r9w :: FromReg c => c S16
- CodeGen.X86: rax :: Operand S64 rw
+ CodeGen.X86: rax :: FromReg c => c S64
- CodeGen.X86: rbp :: Operand S64 rw
+ CodeGen.X86: rbp :: FromReg c => c S64
- CodeGen.X86: rbx :: Operand S64 rw
+ CodeGen.X86: rbx :: FromReg c => c S64
- CodeGen.X86: rcx :: Operand S64 rw
+ CodeGen.X86: rcx :: FromReg c => c S64
- CodeGen.X86: rdi :: Operand S64 rw
+ CodeGen.X86: rdi :: FromReg c => c S64
- CodeGen.X86: rdx :: Operand S64 rw
+ CodeGen.X86: rdx :: FromReg c => c S64
- CodeGen.X86: resizeOperand :: IsSize s' => Operand s RW -> Operand s' RW
+ CodeGen.X86: resizeOperand :: IsSize s' => Operand RW s -> Operand RW s'
- CodeGen.X86: result :: Operand S64 rw
+ CodeGen.X86: result :: FromReg c => c S64
- CodeGen.X86: rsi :: Operand S64 rw
+ CodeGen.X86: rsi :: FromReg c => c S64
- CodeGen.X86: rsp :: Operand S64 rw
+ CodeGen.X86: rsp :: FromReg c => c S64
- CodeGen.X86: si :: Operand S16 rw
+ CodeGen.X86: si :: FromReg c => c S16
- CodeGen.X86: sil :: Operand S8 rw
+ CodeGen.X86: sil :: FromReg c => c S8
- CodeGen.X86: sp :: Operand S16 rw
+ CodeGen.X86: sp :: FromReg c => c S16
- CodeGen.X86: spl :: Operand S8 rw
+ CodeGen.X86: spl :: FromReg c => c S8
- CodeGen.X86: traceReg :: IsSize s => String -> Operand s RW -> Code
+ CodeGen.X86: traceReg :: IsSize s => String -> Operand RW s -> Code

Files

CHANGELOG.md view
@@ -1,3 +1,18 @@+# Version 0.2
+
+-   simpler API for immediate values: `Add ax, 1`
+-   redesigned addressing API: `Add ax (addr $ rax + 4*rdi + 3)`
+-   support near jumps
+-   support automatic decision between short and near jumps (conditional jumps too)
+-   support more registers and instructions:
+    -   cmovCC instructions
+    -   SSE registers: xmm0 - xmm7
+    -   SSE instructions: movd, movq, movdqa, paddb, paddw, paddd, paddq, psubb, psubw, psubd, psubq, pxor
+    -   SSE instructions (partial support): psllw, pslld, psllq, pslldq, psrlw, psrld, psrlq, psrldq, psraw, psraq
+-   bugfixes
+    -   throw an error if an immediate value does not fit
+    -   fix show instance of shift instructions
+
 # Version 0.1.4
 
 -   OS X operating system support (Balázs Kőműves)
CodeGen/X86.hs view
@@ -8,18 +8,16 @@     , Size (..)
     , HasSize (..)
     , IsSize
-    -- * Addresses
-    , base
-    , disp
-    , index1, index2, index4, index8
     -- * Operands
     , Access (..)
     , Operand
     , resizeOperand
-    -- ** Immediate values
-    , imm
     -- ** Memory references
     , addr
+    , addr8
+    , addr16
+    , addr32
+    , addr64
     , ipBase
     -- ** Registers
     -- *** 64 bit registers
@@ -32,15 +30,103 @@     , al, cl, dl, bl, spl, bpl, sil, dil, r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b
     -- *** 8 bit high registers
     , ah, ch, dh, bh
+    -- *** SSE registers
+    , xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
     -- * Conditions
     , Condition
-    , pattern O, pattern NO, pattern C, pattern NC, pattern Z, pattern NZ, pattern BE, pattern NBE, pattern S, pattern NS, pattern P, pattern NP, pattern L, pattern NL, pattern LE, pattern NLE
+    , pattern O
+    , pattern NO
+    , pattern B,  pattern C
+    , pattern NB, pattern NC
+    , pattern E,  pattern Z
+    , pattern NE, pattern NZ
+    , pattern NA, pattern BE
+    , pattern A,  pattern NBE
+    , pattern S
+    , pattern NS
+    , pattern P
+    , pattern NP
+    , pattern L
+    , pattern NL
+    , pattern NG, pattern LE
+    , pattern G,  pattern NLE
     -- * Assembly codes
-    , Code (..)
+    , Code
+    , pattern Ret
+    , pattern Nop
+    , pattern PushF
+    , pattern PopF
+    , pattern Cmc
+    , pattern Clc
+    , pattern Stc
+    , pattern Cli
+    , pattern Sti
+    , pattern Cld
+    , pattern Std
+    , pattern Inc
+    , pattern Dec
+    , pattern Not
+    , pattern Neg
+    , pattern Add
+    , pattern Or
+    , pattern Adc
+    , pattern Sbb
+    , pattern And
+    , pattern Sub
+    , pattern Xor
+    , pattern Cmp
+    , pattern Test
+    , pattern Mov
+    , pattern Cmov
+    , pattern Rol
+    , pattern Ror
+    , pattern Rcl
+    , pattern Rcr
+    , pattern Shl
+    , pattern Shr
+    , pattern Sar
+    , pattern Xchg
+    , pattern Movd
+    , pattern Movq
+    , pattern Movdqa
+    , pattern Paddb
+    , pattern Paddw
+    , pattern Paddd
+    , pattern Paddq
+    , pattern Psubb
+    , pattern Psubw
+    , pattern Psubd
+    , pattern Psubq
+    , pattern Pxor
+    , pattern Psllw
+    , pattern Pslld
+    , pattern Psllq
+    , pattern Pslldq
+    , pattern Psrlw
+    , pattern Psrld
+    , pattern Psrlq
+    , pattern Psrldq
+    , pattern Psraw
+    , pattern Psrad
+    , pattern Lea
+    , pattern J
+    , pattern Pop
+    , pattern Push
+    , pattern Call
+    , pattern Jmpq
+    , pattern Jmp
+    , pattern Data
+    , pattern Align
+    , pattern Label
+    , pattern Scope
+    , pattern Up
     -- * Compound assembly codes
     , (<>)
     , (<.>), (<:>)
-    , j, j_back, if_
+    , jmp, jmp_back, jmp8, jmp32
+    , j, j8, j32
+    , j_back, j_back8, j_back32
+    , if_
     , lea8
     , leaData
     -- * Compilation
CodeGen/X86/Asm.hs view
@@ -14,6 +14,7 @@ {-# language FlexibleContexts #-} {-# language FlexibleInstances #-} {-# language GeneralizedNewtypeDeriving #-}+{-# language StandaloneDeriving #-} module CodeGen.X86.Asm where  import Numeric@@ -41,6 +42,8 @@  showHex' x = "0x" ++ showHex x "" +pattern Integral xs <- (toIntegralSized -> Just xs)+ ------------------------------------------------------- byte sequences  newtype Bytes = Bytes {getBytes :: [Word8]}@@ -69,26 +72,29 @@  ------------------------------------------------------- sizes -data Size = S8 | S16 | S32 | S64+data Size = S8 | S16 | S32 | S64 | S128     deriving (Eq, Ord)  instance Show Size where     show = \case-        S8  -> "byte"-        S16 -> "word"-        S32 -> "dword"-        S64 -> "qword"+        S8   -> "byte"+        S16  -> "word"+        S32  -> "dword"+        S64  -> "qword"+        S128 -> "oword" -mkSize 1 = S8-mkSize 2 = S16-mkSize 4 = S32-mkSize 8 = S64+mkSize  1 = S8+mkSize  2 = S16+mkSize  4 = S32+mkSize  8 = S64+mkSize 16 = S128  sizeLen = \case-    S8  -> 1-    S16 -> 2-    S32 -> 4-    S64 -> 8+    S8   ->  1+    S16  ->  2+    S32  ->  4+    S64  ->  8+    S128 -> 16  class HasSize a where size :: a -> Size @@ -103,25 +109,28 @@  -- | Singleton type for size data SSize (s :: Size) where-    SSize8  :: SSize S8-    SSize16 :: SSize S16-    SSize32 :: SSize S32-    SSize64 :: SSize S64+    SSize8   :: SSize S8+    SSize16  :: SSize S16+    SSize32  :: SSize S32+    SSize64  :: SSize S64+    SSize128 :: SSize S128  instance HasSize (SSize s) where     size = \case-        SSize8  -> S8-        SSize16 -> S16-        SSize32 -> S32-        SSize64 -> S64+        SSize8   -> S8+        SSize16  -> S16+        SSize32  -> S32+        SSize64  -> S64+        SSize128 -> S128  class IsSize (s :: Size) where     ssize :: SSize s -instance IsSize S8  where ssize = SSize8-instance IsSize S16 where ssize = SSize16-instance IsSize S32 where ssize = SSize32-instance IsSize S64 where ssize = SSize64+instance IsSize S8   where ssize = SSize8+instance IsSize S16  where ssize = SSize16+instance IsSize S32  where ssize = SSize32+instance IsSize S64  where ssize = SSize64+instance IsSize S128 where ssize = SSize128  data EqT s s' where     Refl :: EqT s s@@ -145,6 +154,12 @@ s4 = Scale 0x2 s8 = Scale 0x3 +toScale = \case+    1 -> s1+    2 -> s2+    4 -> s4+    8 -> s8+ scaleFactor (Scale i) = case i of     0x0 -> 1     0x1 -> 2@@ -153,14 +168,27 @@  ------------------------------------------------------- operand -data Operand :: Size -> Access -> * where-    ImmOp     :: Immediate Int64 -> Operand s R-    RegOp     :: Reg s -> Operand s rw-    MemOp     :: IsSize s' => Addr s' -> Operand s rw-    IPMemOp   :: Immediate Int32 -> Operand s rw+data Operand :: Access -> Size -> * where+    ImmOp     :: Immediate Int64 -> Operand R s+    RegOp     :: Reg s -> Operand rw s+    MemOp     :: IsSize s' => Addr s' -> Operand rw s+    IPMemOp   :: Immediate Int32 -> Operand rw s -addr = MemOp+addr :: IsSize s => Address s -> Operand rw s'+addr = MemOp . makeAddr +addr8 :: IsSize s => Address s -> Operand rw S8+addr8 = addr++addr16 :: IsSize s => Address s -> Operand rw S16+addr16 = addr++addr32 :: IsSize s => Address s -> Operand rw S32+addr32 = addr++addr64 :: IsSize s => Address s -> Operand rw S64+addr64 = addr+ data Immediate a     = Immediate a     | LabelRelValue Size{-size hint-} !LabelIndex@@ -175,7 +203,11 @@ data Reg :: Size -> * where     NormalReg :: Word8 -> Reg s     HighReg   :: Word8 -> Reg S8+    XMM       :: Word8 -> Reg S128 +deriving instance Eq (Reg s)+deriving instance Ord (Reg s)+ data Addr s = Addr     { baseReg        :: BaseReg s     , displacement   :: Displacement@@ -194,19 +226,15 @@  ipBase = IPMemOp $ LabelRelValue S32 0 -instance Eq (Reg s) where-    NormalReg a == NormalReg b = a == b-    HighReg a == HighReg b = a == b-    _ == _ = False- instance IsSize s => Show (Reg s) where     show = \case+        XMM i -> "xmm" ++ show i         HighReg i -> (["ah"," ch", "dh", "bh"] ++ repeat err) !! fromIntegral i         r@(NormalReg i) -> (!! fromIntegral i) . (++ repeat err) $ case size r of-            S8  -> ["al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"] ++ map (++ "b") r8-            S16 -> r0 ++ map (++ "w") r8-            S32 -> map ('e':) r0 ++ map (++ "d") r8-            S64 -> map ('r':) r0 ++ r8+            S8   -> ["al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"] ++ map (++ "b") r8+            S16  -> r0 ++ map (++ "w") r8+            S32  -> map ('e':) r0 ++ map (++ "d") r8+            S64  -> map ('r':) r0 ++ r8           where             r0 = ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"]             r8 = ["r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"]@@ -231,7 +259,7 @@         f True = " + "         f False = " - " -instance IsSize s => Show (Operand s a) where+instance IsSize s => Show (Operand a s) where     show = showOperand show  showOperand mklab = \case@@ -247,12 +275,15 @@     showImm (Immediate x) = show x     showImm (LabelRelValue _ x) = mklab x -instance IsSize s => HasSize (Operand s a) where+instance IsSize s => HasSize (Operand a s) where     size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (Addr s) where     size _ = size (ssize :: SSize s) +instance IsSize s => HasSize (Address s) where+    size _ = size (ssize :: SSize s)+ instance IsSize s => HasSize (BaseReg s) where     size _ = size (ssize :: SSize s) @@ -262,9 +293,13 @@ instance IsSize s => HasSize (IndexReg s) where     size _ = size (ssize :: SSize s) -imm :: Integral a => a -> Operand s R-imm = ImmOp . Immediate . fromIntegral+imm :: (Integral a, Bits a) => a -> Operand R s+imm (Integral x) = ImmOp $ Immediate x +instance (rw ~ R) => Num (Operand rw s) where+    negate (ImmOp (Immediate x)) = imm (negate x)+    fromInteger = imm+ instance Monoid (Addr s) where     mempty = Addr (getFirst mempty) (getFirst mempty) (getFirst mempty)     Addr a b c `mappend` Addr a' b' c' = Addr (getFirst $ First a <> First a') (getFirst $ First b <> First b') (getFirst $ First c <> First c')@@ -274,23 +309,67 @@     i `mappend` NoIndex = i     NoIndex `mappend` i = i -base :: Operand s RW -> Addr s-base (RegOp x) = Addr (Just x) NoDisp NoIndex+base :: Reg s -> Addr s+base x = Addr (Just x) NoDisp NoIndex -index :: Scale -> Operand s RW -> Addr s-index sc (RegOp x) = Addr Nothing NoDisp (IndexReg sc x)+index :: Scale -> Reg s -> Addr s+index sc x = Addr Nothing NoDisp (IndexReg sc x) +index' :: Int -> Reg s -> Addr s+index' sc x = Addr Nothing NoDisp (IndexReg (toScale sc) x)+ index1 = index s1 index2 = index s2 index4 = index s4 index8 = index s8 -disp :: Int32 -> Addr s-disp x = Addr Nothing (Disp x) NoIndex+disp :: (Bits a, Integral a) => a -> Addr s+disp (Integral x)+    | x == 0 = mempty+    | otherwise = Addr Nothing (Disp x) NoIndex -reg = RegOp . NormalReg+data Address :: Size -> * where+    Address :: [(Int, Reg s)] -> Int -> Address s -rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 :: Operand S64 rw+scaleAddress :: (Int -> Int) -> Address s -> Address s+scaleAddress f (Address rs d) = Address (first f <$> rs) $ f d++instance Num (Address s) where+    fromInteger d = Address [] $ fromInteger d+    negate = scaleAddress negate+    Address [] t * a = scaleAddress (t*) a+    a * Address [] t = scaleAddress (t*) a+    Address rs d + Address rs' d' = Address (f rs rs') (d + d') where+        f [] rs = rs+        f rs [] = rs+        f (p@(t, r): rs) (p'@(t', r'): rs') = case compare r r' of+            LT -> p: f rs (p': rs')+            GT -> p': f (p: rs) rs'+            EQ | t + t' == 0 -> f rs rs'+               | otherwise   -> (t + t', r): f rs rs'++makeAddr :: Address s -> Addr s+makeAddr (Address [(1, r)] d) = base r <> disp d+makeAddr (Address [(t, r)] d) = index' t r <> disp d+makeAddr (Address [(1, r), (1, r'@(NormalReg 0x4))] d) = base r' <> index1 r <> disp d+makeAddr (Address [(1, r), (t, r')] d) = base r <> index' t r' <> disp d+makeAddr (Address [(t, r'), (1, r)] d) = base r <> index' t r' <> disp d++class FromReg c where+    fromReg :: Reg s -> c s++instance FromReg Reg where+    fromReg = id++instance FromReg (Operand r) where+    fromReg = RegOp++instance FromReg Address where+    fromReg r = Address [(1, r)] 0++reg = fromReg . NormalReg++rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 :: FromReg c => c S64 rax  = reg 0x0 rcx  = reg 0x1 rdx  = reg 0x2@@ -308,7 +387,7 @@ r14  = reg 0xe r15  = reg 0xf -eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d :: Operand S32 rw+eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d :: FromReg c => c S32 eax  = reg 0x0 ecx  = reg 0x1 edx  = reg 0x2@@ -326,7 +405,7 @@ r14d = reg 0xe r15d = reg 0xf -ax, cx, dx, bx, sp, bp, si, di, r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w :: Operand S16 rw+ax, cx, dx, bx, sp, bp, si, di, r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w :: FromReg c => c S16 ax   = reg 0x0 cx   = reg 0x1 dx   = reg 0x2@@ -344,7 +423,7 @@ r14w = reg 0xe r15w = reg 0xf -al, cl, dl, bl, spl, bpl, sil, dil, r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b :: Operand S8 rw+al, cl, dl, bl, spl, bpl, sil, dil, r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b :: FromReg c => c S8 al   = reg 0x0 cl   = reg 0x1 dl   = reg 0x2@@ -362,19 +441,30 @@ r14b = reg 0xe r15b = reg 0xf -ah   = RegOp $ HighReg 0x0-ch   = RegOp $ HighReg 0x1-dh   = RegOp $ HighReg 0x2-bh   = RegOp $ HighReg 0x3+ah, ch, dh, bh :: FromReg c => c S8+ah   = fromReg $ HighReg 0x0+ch   = fromReg $ HighReg 0x1+dh   = fromReg $ HighReg 0x2+bh   = fromReg $ HighReg 0x3 +xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 :: FromReg c => c S128+xmm0 = fromReg $ XMM 0x0+xmm1 = fromReg $ XMM 0x1+xmm2 = fromReg $ XMM 0x2+xmm3 = fromReg $ XMM 0x3+xmm4 = fromReg $ XMM 0x4+xmm5 = fromReg $ XMM 0x5+xmm6 = fromReg $ XMM 0x6+xmm7 = fromReg $ XMM 0x7+ pattern RegA = RegOp (NormalReg 0x0) -pattern RegCl :: Operand S8 r+pattern RegCl :: Operand r S8 pattern RegCl = RegOp (NormalReg 0x1)  -------------------------------------------------------------- -resizeOperand :: IsSize s' => Operand s RW -> Operand s' RW+resizeOperand :: IsSize s' => Operand RW s -> Operand RW s' resizeOperand (RegOp x) = RegOp $ resizeRegCode x resizeOperand (MemOp a) = MemOp a resizeOperand (IPMemOp a) = IPMemOp a@@ -436,56 +526,38 @@         0xe -> "le"         0xf -> "nle" --------------------------------------------------------------- asm code--data Code where-    Ret, Nop, PushF, PopF, Cmc, Clc, Stc, Cli, Sti, Cld, Std   :: Code--    Inc, Dec, Not, Neg                                :: IsSize s => Operand s RW -> Code-    Add, Or, Adc, Sbb, And, Sub, Xor, Cmp, Test, Mov  :: IsSize s => Operand s RW -> Operand s  r -> Code-    Rol, Ror, Rcl, Rcr, Shl, Shr, Sar                 :: IsSize s => Operand s RW -> Operand S8 r -> Code--    Xchg :: IsSize s => Operand s RW -> Operand s RW -> Code-    Lea  :: (IsSize s, IsSize s') => Operand s RW -> Operand s' RW -> Code--    Pop  :: Operand S64 RW -> Code-    Push :: Operand S64 r  -> Code--    Call :: Operand S64 RW -> Code-    Jmpq :: Operand S64 RW -> Code--    J    :: Maybe Size -> Condition -> Code-    Jmp  :: Code+-------------------------------------------------------------- asm code lines -    Label :: Code-    Scope :: Code -> Code-    Up    :: Code -> Code+data CodeLine where+    Ret_, Nop_, PushF_, PopF_, Cmc_, Clc_, Stc_, Cli_, Sti_, Cld_, Std_   :: CodeLine -    Data  :: Bytes -> Code-    Align :: Size  -> Code+    Inc_, Dec_, Not_, Neg_                                :: IsSize s => Operand RW s -> CodeLine+    Add_, Or_, Adc_, Sbb_, And_, Sub_, Xor_, Cmp_, Test_, Mov_  :: IsSize s => Operand RW s -> Operand r s -> CodeLine+    Rol_, Ror_, Rcl_, Rcr_, Shl_, Shr_, Sar_                 :: IsSize s => Operand RW s -> Operand r S8 -> CodeLine -    EmptyCode  :: Code-    AppendCode :: Code -> Code -> Code+    Movdqa_, Paddb_, Paddw_, Paddd_, Paddq_, Psubb_, Psubw_, Psubd_, Psubq_, Pxor_ :: Operand RW S128 -> Operand r S128 -> CodeLine+    Psllw_, Pslld_, Psllq_, Pslldq_, Psrlw_, Psrld_, Psrlq_, Psrldq_, Psraw_, Psrad_ :: Operand RW S128 -> Operand r S8 -> CodeLine+    Movd_, Movq_ :: (IsSize s, IsSize s') => Operand RW s -> Operand r s' -> CodeLine -instance Monoid Code where-    mempty  = EmptyCode-    mappend = AppendCode+    Cmov_ :: IsSize s => Condition -> Operand RW s -> Operand RW s -> CodeLine+    Xchg_ :: IsSize s => Operand RW s -> Operand RW s -> CodeLine+    Lea_  :: (IsSize s, IsSize s') => Operand RW s -> Operand RW s' -> CodeLine --------------+    Pop_  :: Operand RW S64 -> CodeLine+    Push_ :: Operand r  S64 -> CodeLine -showCode = \case-    EmptyCode  -> return ()-    AppendCode a b -> showCode a >> showCode b+    Call_ :: Operand RW S64 -> CodeLine+    Jmpq_ :: Operand RW S64 -> CodeLine -    Scope c -> get >>= \i -> put (i+1) >> local (i:) (showCode c)+    J_    :: Condition -> Maybe Size -> CodeLine+    Jmp_  :: Maybe Size -> CodeLine -    Up c -> local tail $ showCode c+    Label_ :: CodeLine -    J s cc -> getLabel 0 >>= \l -> showOp ("j" ++ show cc) $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ l-    Jmp   -> getLabel 0 >>= \l -> showOp "jmp" l-    Label -> getLabel 0 >>= codeLine+    Data_  :: Bytes -> CodeLine+    Align_ :: Int   -> CodeLine -    x -> showCodeFrag x+------------------------- show code lines  getLabel i = ($ i) <$> getLabels @@ -497,55 +569,82 @@  codeLine x = tell [x] -showCodeFrag = \case-    Add  op1 op2 -> showOp2 "add"  op1 op2-    Or   op1 op2 -> showOp2 "or"   op1 op2-    Adc  op1 op2 -> showOp2 "adc"  op1 op2-    Sbb  op1 op2 -> showOp2 "sbb"  op1 op2-    And  op1 op2 -> showOp2 "and"  op1 op2-    Sub  op1 op2 -> showOp2 "sub"  op1 op2-    Xor  op1 op2 -> showOp2 "xor"  op1 op2-    Cmp  op1 op2 -> showOp2 "cmp"  op1 op2-    Test op1 op2 -> showOp2 "test" op1 op2-    Rol  op1 op2 -> showOp2 "rol"  op1 op2-    Ror  op1 op2 -> showOp2 "rol"  op1 op2-    Rcl  op1 op2 -> showOp2 "rol"  op1 op2-    Rcr  op1 op2 -> showOp2 "rol"  op1 op2-    Shl  op1 op2 -> showOp2 "rol"  op1 op2-    Shr  op1 op2 -> showOp2 "rol"  op1 op2-    Sar  op1 op2 -> showOp2 "rol"  op1 op2-    Mov  op1 op2 -> showOp2 "mov"  op1 op2-    Lea  op1 op2 -> showOp2 "lea"  op1 op2-    Xchg op1 op2 -> showOp2 "xchg" op1 op2-    Inc  op -> showOp1 "inc"  op-    Dec  op -> showOp1 "dec"  op-    Not  op -> showOp1 "not"  op-    Neg  op -> showOp1 "neg"  op-    Pop  op -> showOp1 "pop"  op-    Push op -> showOp1 "push" op-    Call op -> showOp1 "call" op-    Jmpq op -> showOp1 "jmp"  op-    Ret   -> showOp0 "ret"-    Nop   -> showOp0 "nop"-    PushF -> showOp0 "pushf"-    PopF  -> showOp0 "popf"-    Cmc   -> showOp0 "cmc"-    Clc   -> showOp0 "clc"-    Stc   -> showOp0 "stc"-    Cli   -> showOp0 "cli"-    Sti   -> showOp0 "sti"-    Cld   -> showOp0 "cld"-    Std   -> showOp0 "std"+showOp0 s = codeLine s+showOp s a = showOp0 $ s ++ " " ++ a+showOp1 s a = getLabels >>= \f -> showOp s $ showOperand f a+showOp2 s a b = getLabels >>= \f -> showOp s $ showOperand f a ++ ", " ++ showOperand f b -    Align s -> codeLine $ ".align " ++ show s-    Data (Bytes x)+showCodeLine = \case+    Add_  op1 op2 -> showOp2 "add"  op1 op2+    Or_   op1 op2 -> showOp2 "or"   op1 op2+    Adc_  op1 op2 -> showOp2 "adc"  op1 op2+    Sbb_  op1 op2 -> showOp2 "sbb"  op1 op2+    And_  op1 op2 -> showOp2 "and"  op1 op2+    Sub_  op1 op2 -> showOp2 "sub"  op1 op2+    Xor_  op1 op2 -> showOp2 "xor"  op1 op2+    Cmp_  op1 op2 -> showOp2 "cmp"  op1 op2+    Test_ op1 op2 -> showOp2 "test" op1 op2+    Rol_  op1 op2 -> showOp2 "rol"  op1 op2+    Ror_  op1 op2 -> showOp2 "ror"  op1 op2+    Rcl_  op1 op2 -> showOp2 "rcl"  op1 op2+    Rcr_  op1 op2 -> showOp2 "rcr"  op1 op2+    Shl_  op1 op2 -> showOp2 "shl"  op1 op2+    Shr_  op1 op2 -> showOp2 "shr"  op1 op2+    Sar_  op1 op2 -> showOp2 "sar"  op1 op2+    Mov_  op1 op2 -> showOp2 "mov"  op1 op2+    Cmov_ cc op1 op2 -> showOp2 ("cmov" ++ show cc) op1 op2+    Lea_  op1 op2 -> showOp2 "lea"  op1 op2+    Xchg_ op1 op2 -> showOp2 "xchg" op1 op2+    Movd_   op1 op2 -> showOp2 "movd"   op1 op2+    Movq_   op1 op2 -> showOp2 "movq"   op1 op2+    Movdqa_ op1 op2 -> showOp2 "movdqa" op1 op2+    Paddb_  op1 op2 -> showOp2 "paddb"  op1 op2+    Paddw_  op1 op2 -> showOp2 "paddw"  op1 op2+    Paddd_  op1 op2 -> showOp2 "paddd"  op1 op2+    Paddq_  op1 op2 -> showOp2 "paddq"  op1 op2+    Psubb_  op1 op2 -> showOp2 "psubb"  op1 op2+    Psubw_  op1 op2 -> showOp2 "psubw"  op1 op2+    Psubd_  op1 op2 -> showOp2 "psubd"  op1 op2+    Psubq_  op1 op2 -> showOp2 "psubq"  op1 op2+    Pxor_   op1 op2 -> showOp2 "pxor"   op1 op2+    Psllw_  op1 op2 -> showOp2 "psllw"  op1 op2+    Pslld_  op1 op2 -> showOp2 "pslld"  op1 op2+    Psllq_  op1 op2 -> showOp2 "psllq"  op1 op2+    Pslldq_ op1 op2 -> showOp2 "pslldq" op1 op2+    Psrlw_  op1 op2 -> showOp2 "psrlw"  op1 op2+    Psrld_  op1 op2 -> showOp2 "psrld"  op1 op2+    Psrlq_  op1 op2 -> showOp2 "psrlq"  op1 op2+    Psrldq_ op1 op2 -> showOp2 "psrldq" op1 op2+    Psraw_  op1 op2 -> showOp2 "psraw"  op1 op2+    Psrad_  op1 op2 -> showOp2 "psrad"  op1 op2+    Inc_  op -> showOp1 "inc"  op+    Dec_  op -> showOp1 "dec"  op+    Not_  op -> showOp1 "not"  op+    Neg_  op -> showOp1 "neg"  op+    Pop_  op -> showOp1 "pop"  op+    Push_ op -> showOp1 "push" op+    Call_ op -> showOp1 "call" op+    Jmpq_ op -> showOp1 "jmp"  op+    Ret_   -> showOp0 "ret"+    Nop_   -> showOp0 "nop"+    PushF_ -> showOp0 "pushf"+    PopF_  -> showOp0 "popf"+    Cmc_   -> showOp0 "cmc"+    Clc_   -> showOp0 "clc"+    Stc_   -> showOp0 "stc"+    Cli_   -> showOp0 "cli"+    Sti_   -> showOp0 "sti"+    Cld_   -> showOp0 "cld"+    Std_   -> showOp0 "std"++    Align_ s -> codeLine $ ".align " ++ show s+    Data_ (Bytes x)         | 2 * length (filter isPrint x) > length x -> showOp "db" $ show (toEnum . fromIntegral <$> x :: String)         | otherwise -> showOp "db" $ intercalate ", " (show <$> x)       where         isPrint c = c >= 32 && c <= 126 -showOp0 s = codeLine s-showOp s a = showOp0 $ s ++ " " ++ a-showOp1 s a = getLabels >>= \f -> showOp s $ showOperand f a-showOp2 s a b = getLabels >>= \f -> showOp s $ showOperand f a ++ ", " ++ showOperand f b+    J_ cc s -> getLabel 0 >>= \l -> showOp ("j" ++ show cc) $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ l+    Jmp_ s  -> getLabel 0 >>= \l -> showOp "jmp" $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ l+    Label_  -> getLabel 0 >>= codeLine 
CodeGen/X86/CallConv.hs view
@@ -1,6 +1,6 @@- -- | Calling conventions. There are basically only two: System V (Linux, OSX, BSD) and Win64\/fastcall +{-# language NoMonomorphismRestriction #-} {-# language CPP #-} {-# language BangPatterns #-} {-# language DataKinds #-}@@ -8,31 +8,33 @@  import Foreign import Data.Monoid+ import CodeGen.X86.Asm+import CodeGen.X86.CodeGen  ------------------------------------------------------------------------------   #if defined (mingw32_HOST_OS) || defined (mingw64_HOST_OS)  -- On Win64 the caller have to reserve 32 byte "shadow space" on the stack (and clean up after)-callFun :: Operand S64 RW -> FunPtr a -> Code+callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p -  =  Sub rsp (imm 32) -  <> Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  =  Sub rsp 32+  <> Mov r (imm $ ptrToIntPtr $ castFunPtrToPtr p)   <> Call r -  <> Add rsp (imm 32)+  <> Add rsp 32  #elif defined (darwin_HOST_OS)  -- OSX requires 16 byte alignment of the stack...-callFun :: Operand S64 RW -> FunPtr a -> Code+callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p    =  Push r15              -- we will use r15 (non-volatile) to store old rsp-  <> Mov r15 (imm 15)      -- 0xf+  <> Mov r15 15            -- 0xf   <> Not r15               -- 0xffff ... fff0   <> And r15 rsp           -- align rsp into r15   <> Xchg r15 rsp          -- new rsp = aligned, r15 = old rsp-  <> Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  <> Mov r (imm $ ptrToIntPtr $ castFunPtrToPtr p)   <> Call r    <> Mov rsp r15           -- restore rsp   <> Pop r15               -- restore r15@@ -40,9 +42,9 @@ #else  -- helper to call a function-callFun :: Operand S64 RW -> FunPtr a -> Code+callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p -  =  Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) +  =  Mov r (imm $ ptrToIntPtr $ castFunPtrToPtr p)   <> Call r  #endif
CodeGen/X86/CodeGen.hs view
@@ -45,8 +45,6 @@ pattern FJust a = First (Just a) pattern FNothing = First Nothing -pattern Integral xs <- (toIntegralSized -> Just xs)- integralToBytes :: (Bits a, Integral a) => Bool{-signed-} -> Size -> a -> Maybe Bytes integralToBytes False S64 w = toBytes <$> (toIntegralSized w :: Maybe Word64) integralToBytes False S32 w = toBytes <$> (toIntegralSized w :: Maybe Word32)@@ -69,7 +67,7 @@ isHigh (SReg HighReg{}) = True isHigh _ = False -regs :: forall s k . IsSize s => Operand s k -> [SReg]+regs :: IsSize s => Operand r s -> [SReg] regs = \case     MemOp (Addr r _ i) -> foldMap (pure . SReg) r ++ foldMap (pure . SReg . snd) i     RegOp r -> [SReg r]@@ -86,20 +84,22 @@ ------------------------------------------------------- code builder  data CodeBuilder-    = CodeBuilder (CodeBuilderState -> (CodeBuilderRes, CodeBuilderState))-    | ExactCodeBuilder Int (CodeBuilderState -> (CodeBuilderRes, LabelState))   -- ^ CodeBuilder with known length+    = CodeBuilder !Int !Int (CodeBuilderState -> (CodeBuilderRes, CodeBuilderState)) +pattern ExactCodeBuilder len f <- (getExactCodeBuilder -> Just (len, f))+  where ExactCodeBuilder len f = CodeBuilder len len $ \st@(n, _) -> second ((,) (n + len)) $ f st++getExactCodeBuilder (CodeBuilder i j f) | i == j = Just (i, second snd . f)+getExactCodeBuilder _ = Nothing+ codeBuilderLength (ExactCodeBuilder len _) = len  buildCode :: CodeBuilder -> CodeBuilderState -> (CodeBuilderRes, CodeBuilderState)-buildCode (CodeBuilder f) st = f st-buildCode (ExactCodeBuilder len f) (n, st) = second ((,) (n + len)) $ f (n, st)+buildCode (CodeBuilder _ _ f) st = f st -mapLabelState g (CodeBuilder f) = CodeBuilder $ \(n, g -> (fx, xs)) -> second (second fx) $ f (n, xs)-mapLabelState g (ExactCodeBuilder len f) = ExactCodeBuilder len $ \(n, g -> (fx, xs)) -> second fx $ f (n, xs)+mapLabelState g (CodeBuilder i j f) = CodeBuilder i j $ \(n, g -> (fx, xs)) -> second (second fx) $ f (n, xs) -censorCodeBuilder g (CodeBuilder f) = CodeBuilder $ \st -> first (g st) $ f st-censorCodeBuilder g (ExactCodeBuilder len f) = ExactCodeBuilder len $ \st -> first (g st) $ f st+censorCodeBuilder g (CodeBuilder i j f) = CodeBuilder i j $ \st -> first (g st) $ f st  type CodeBuilderRes = [Either Int (Int, Word8)] @@ -109,12 +109,13 @@  instance Monoid CodeBuilder where     mempty = ExactCodeBuilder 0 $ \(_, st) -> (mempty, st)-    ExactCodeBuilder len f `mappend` ExactCodeBuilder len' g = ExactCodeBuilder (len + len') $ \st -> let-            (a, st') = f st-            (b, st'') = g (len + fst st, st')-        in (a ++ b, st'')-    f `mappend` g = CodeBuilder $ \(buildCode f -> (a, buildCode g -> (b, st))) -> (a ++ b, st)+    f `mappend` g = CodeBuilder (i1+i2) (j1+j2) $ \(buildCode f -> (a, buildCode g -> (b, st))) -> (a ++ b, st)+      where+        (i1, j1) = bounds f+        (i2, j2) = bounds g +bounds (CodeBuilder i j _) = (i, j)+ codeByte :: Word8 -> CodeBuilder codeByte c = ExactCodeBuilder 1 $ \(n, labs) -> ([Right (n, c)], labs) @@ -138,8 +139,10 @@             labs' = take bs labs ++ Left ((s, n, - n - offset): cs): drop (bs + 1) labs  mkAutoRef :: [(Size, Bytes)] -> Int -> Int -> CodeBuilder-mkAutoRef ss offset bs = CodeBuilder f+mkAutoRef ss offset bs = CodeBuilder (minimum sizes) (maximum sizes) f   where+    sizes = map (\(s, c) -> sizeLen s + bytesCount c) ss+     f (n, labs) | bs >= length labs = error "missing scope"     f (n, labs) = case labs !! bs of         Left cs -> error "auto length computation for forward references is not supported"@@ -183,7 +186,7 @@ mkCodeBuilder :: Code -> CodeBuilder mkCodeBuilder = \case     EmptyCode -> mempty-    AppendCode a b -> mkCodeBuilder a <> mkCodeBuilder b+    AppendCode cb _ _ -> cb      Up a -> mapLabelState (\(x: xs) -> ((x:), xs)) $ mkCodeBuilder a @@ -193,86 +196,114 @@         end (n, Right _: labs) = (mempty, labs)         end (n, _: labs) = trace "warning: missing label" (mempty, labs) -    x -> censorCodeBuilder (\(addr, _) -> (Left addr:)) $ mkCodeBuilder' x+    CodeLine_ cb _ -> censorCodeBuilder (\(addr, _) -> (Left addr:)) cb -mkCodeBuilder' :: Code -> CodeBuilder+mkCodeBuilder' :: CodeLine -> CodeBuilder mkCodeBuilder' = \case-    Add  a b -> op2 0x0 a b-    Or   a b -> op2 0x1 a b-    Adc  a b -> op2 0x2 a b-    Sbb  a b -> op2 0x3 a b-    And  a b -> op2 0x4 a b-    Sub  a b -> op2 0x5 a b-    Xor  a b -> op2 0x6 a b-    Cmp  a b -> op2 0x7 a b+    Add_  a b -> op2 0x0 a b+    Or_   a b -> op2 0x1 a b+    Adc_  a b -> op2 0x2 a b+    Sbb_  a b -> op2 0x3 a b+    And_  a b -> op2 0x4 a b+    Sub_  a b -> op2 0x5 a b+    Xor_  a b -> op2 0x6 a b+    Cmp_  a b -> op2 0x7 a b -    Rol a b -> shiftOp 0x0 a b-    Ror a b -> shiftOp 0x1 a b-    Rcl a b -> shiftOp 0x2 a b-    Rcr a b -> shiftOp 0x3 a b-    Shl a b -> shiftOp 0x4 a b -- sal-    Shr a b -> shiftOp 0x5 a b-    Sar a b -> shiftOp 0x7 a b+    Rol_ a b -> shiftOp 0x0 a b+    Ror_ a b -> shiftOp 0x1 a b+    Rcl_ a b -> shiftOp 0x2 a b+    Rcr_ a b -> shiftOp 0x3 a b+    Shl_ a b -> shiftOp 0x4 a b -- sal+    Shr_ a b -> shiftOp 0x5 a b+    Sar_ a b -> shiftOp 0x7 a b -    Xchg x@RegA r -> xchg_a r-    Xchg r x@RegA -> xchg_a r-    Xchg dest src -> op2' 0x43 dest' src+    Xchg_ x@RegA r -> xchg_a r+    Xchg_ r x@RegA -> xchg_a r+    Xchg_ dest src -> op2' 0x43 dest' src       where         (dest', src') = if isMemOp src then (src, dest) else (dest, src) -    Test dest (mkImmNo64 (size dest) -> FJust (_, im)) -> case dest of+    Test_ dest (mkImmNo64 (size dest) -> FJust (_, im)) -> case dest of         RegA -> regprefix'' dest 0x54 mempty im         _ -> regprefix'' dest 0x7b (reg8 0x0 dest) im-    Test dest (noImm "" -> src) -> op2' 0x42 dest' src'+    Test_ dest (noImm "" -> src) -> op2' 0x42 dest' src'       where         (dest', src') = if isMemOp src then (src, dest) else (dest, src) -    Mov dest@(RegOp r) ((if size dest == S64 then mkImm S32 <> mkImmS S32 <> mkImmS S64 else mkImmS (size dest)) -> FJust ((se, si), im))+    Mov_ dest@(RegOp r) ((if size dest == S64 then mkImm S32 <> mkImmS S32 <> mkImmS S64 else mkImmS (size dest)) -> FJust ((se, si), im))         | (se, si, size dest) /= (True, S32, S64) -> regprefix si dest (oneReg (0x16 .|. indicator (size dest /= S8)) r) im         | otherwise -> regprefix'' dest 0x63 (reg8 0x0 dest) im-    Mov dest@(size -> s) (mkImmNo64 s -> FJust (_, im)) -> regprefix'' dest 0x63 (reg8 0x0 dest) im-    Mov dest src -> op2' 0x44 dest $ noImm (show (dest, src)) src+    Mov_ dest@(size -> s) (mkImmNo64 s -> FJust (_, im)) -> regprefix'' dest 0x63 (reg8 0x0 dest) im+    Mov_ dest src -> op2' 0x44 dest $ noImm (show (dest, src)) src -    Lea dest@(RegOp r) src | size dest /= S8 -> regprefix2 (resizeOperand' dest src) dest 0x46 $ reg8 (reg8_ r) src+    Cmov_ (Condition c) dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte (0x40 .|. c) <> reg2x8 dest src++    Lea_ dest src | size dest /= S8 -> regprefix2' (resizeOperand' dest src) dest 0x46 $ reg2x8 dest src       where-        resizeOperand' :: IsSize s1 => Operand s1 x -> Operand s2 RW -> Operand s1 RW+        resizeOperand' :: IsSize s1 => Operand x s1 -> Operand RW s2 -> Operand RW s1         resizeOperand' _ = resizeOperand -    Not  a -> op1 0x7b 0x2 a-    Neg  a -> op1 0x7b 0x3 a-    Inc  a -> op1 0x7f 0x0 a-    Dec  a -> op1 0x7f 0x1 a-    Call a -> op1' 0xff 0x2 a-    Jmpq a -> op1' 0xff 0x4 a+    Not_  a -> op1 0x7b 0x2 a+    Neg_  a -> op1 0x7b 0x3 a+    Inc_  a -> op1 0x7f 0x0 a+    Dec_  a -> op1 0x7f 0x1 a+    Call_ a -> op1' 0xff 0x2 a+    Jmpq_ a -> op1' 0xff 0x4 a -    Pop dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0b r) mempty-    Pop dest -> regprefix S32 dest (codeByte 0x8f <> reg8 0x0 dest) mempty+    Movd_ a@OpXMM b -> sse 0x6e a b+    Movd_ b a@OpXMM -> sse 0x7e a b+    Movq_ b a@OpXMM -> sse 0xd6 a b+    Movdqa_ a@OpXMM b -> sse 0x6f a b+    Movdqa_ b a@OpXMM -> sse 0x7f a b+    Paddb_  a b -> sse 0xfc a b+    Paddw_  a b -> sse 0xfd a b+    Paddd_  a b -> sse 0xfe a b+    Paddq_  a b -> sse 0xd4 a b+    Psubb_  a b -> sse 0xf8 a b+    Psubw_  a b -> sse 0xf9 a b+    Psubd_  a b -> sse 0xfa a b+    Psubq_  a b -> sse 0xfb a b+    Pxor_   a b -> sse 0xef a b+    Psllw_  a b -> sseShift 0x71 0x2 0xd1 a b+    Pslld_  a b -> sseShift 0x72 0x2 0xd2 a b+    Psllq_  a b -> sseShift 0x73 0x2 0xd3 a b+    Pslldq_ a b -> sseShift 0x73 0x7 undefined a b+    Psrlw_  a b -> sseShift 0x71 0x6 0xf1 a b+    Psrld_  a b -> sseShift 0x72 0x6 0xf2 a b+    Psrlq_  a b -> sseShift 0x73 0x6 0xf3 a b+    Psrldq_ a b -> sseShift 0x73 0x3 undefined a b+    Psraw_  a b -> sseShift 0x71 0x4 0xe1 a b+    Psrad_  a b -> sseShift 0x72 0x4 0xe2 a b -    Push (mkImmS S8 -> FJust (_, im))  -> codeByte 0x6a <> im-    Push (mkImmS S32 -> FJust (_, im)) -> codeByte 0x68 <> im-    Push dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0a r) mempty-    Push dest -> regprefix S32 dest (codeByte 0xff <> reg8 0x6 dest) mempty+    Pop_ dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0b r) mempty+    Pop_ dest -> regprefix S32 dest (codeByte 0x8f <> reg8 0x0 dest) mempty -    Ret   -> codeByte 0xc3-    Nop   -> codeByte 0x90-    PushF -> codeByte 0x9c-    PopF  -> codeByte 0x9d-    Cmc   -> codeByte 0xf5-    Clc   -> codeByte 0xf8-    Stc   -> codeByte 0xf9-    Cli   -> codeByte 0xfa-    Sti   -> codeByte 0xfb-    Cld   -> codeByte 0xfc-    Std   -> codeByte 0xfd+    Push_ (mkImmS S8 -> FJust (_, im))  -> codeByte 0x6a <> im+    Push_ (mkImmS S32 -> FJust (_, im)) -> codeByte 0x68 <> im+    Push_ dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0a r) mempty+    Push_ dest -> regprefix S32 dest (codeByte 0xff <> reg8 0x6 dest) mempty -    J (Just S8)  (Condition c) -> codeByte (0x70 .|. c) <> mkRef S8 1 0-    J (Just S32) (Condition c) -> codeByte 0x0f <> codeByte (0x80 .|. c) <> mkRef S32 4 0-    J Nothing    (Condition c) -> mkAutoRef [(S8, Bytes [0x70 .|. c]), (S32, Bytes [0x0f, 0x80 .|. c])] 0 0+    Ret_   -> codeByte 0xc3+    Nop_   -> codeByte 0x90+    PushF_ -> codeByte 0x9c+    PopF_  -> codeByte 0x9d+    Cmc_   -> codeByte 0xf5+    Clc_   -> codeByte 0xf8+    Stc_   -> codeByte 0xf9+    Cli_   -> codeByte 0xfa+    Sti_   -> codeByte 0xfb+    Cld_   -> codeByte 0xfc+    Std_   -> codeByte 0xfd -    -- short jump-    Jmp -> codeByte 0xeb <> mkRef S8 1 0+    J_ (Condition c) (Just S8)  -> codeByte (0x70 .|. c) <> mkRef S8 1 0+    J_ (Condition c) (Just S32) -> codeByte 0x0f <> codeByte (0x80 .|. c) <> mkRef S32 4 0+    J_ (Condition c) Nothing    -> mkAutoRef [(S8, Bytes [0x70 .|. c]), (S32, Bytes [0x0f, 0x80 .|. c])] 0 0 -    Label -> ExactCodeBuilder 0 lab+    Jmp_ (Just S8)  -> codeByte 0xeb <> mkRef S8 1 0+    Jmp_ (Just S32) -> codeByte 0xe9 <> mkRef S32 4 0+    Jmp_ Nothing    -> mkAutoRef [(S8, Bytes [0xeb]), (S32, Bytes [0xe9])] 0 0++    Label_ -> ExactCodeBuilder 0 lab       where         lab :: CodeBuilderState -> (CodeBuilderRes, LabelState)         lab (n, labs) = (Right <$> concatMap g corr, labs')@@ -282,55 +313,55 @@             g (size, p, v) = zip [p..] $ getBytes $ case (size, v + n) of                 (S8, Integral v) -> toBytes (v :: Int8)                 (S32, Integral v) -> toBytes (v :: Int32)+                (s, i) -> error $ show i ++ " doesn't fit into " ++ show s              replL x (Left z: zs) = (z, x: zs)             replL x (z: zs) = second (z:) $ replL x zs -    Data x -> bytesToCodeBuilder x-    Align s -> CodeBuilder $ \(n, labs) -> let-                    n' = fromIntegral $ (fromIntegral n - 1 :: Int64) .|. f s + 1+    Data_ x -> bytesToCodeBuilder x+    Align_ s -> CodeBuilder 0 s $ \(n, labs) -> let+                    n' = fromIntegral $ ((fromIntegral n - 1 :: Int64) .|. (fromIntegral s - 1)) + 1                 in (Right <$> zip [n..] (replicate (n' - n) 0x90), (n', labs))-      where-        f :: Size -> Int64-        f s = sizeLen s - 1   where-    convertImm :: Bool{-signed-} -> Size -> Operand s k -> First ((Bool, Size), CodeBuilder)+    convertImm :: Bool{-signed-} -> Size -> Operand r s -> First ((Bool, Size), CodeBuilder)     convertImm a b (ImmOp (Immediate c)) = First $ (,) (a, b) . bytesToCodeBuilder <$> integralToBytes a b c     convertImm True b (ImmOp (LabelRelValue s d)) | b == s = FJust $ (,) (True, b) $ mkRef s (sizeLen s) d     convertImm _ _ _ = FNothing -    mkImmS, mkImm, mkImmNo64 :: Size -> Operand s k -> First ((Bool, Size), CodeBuilder)+    mkImmS, mkImm, mkImmNo64 :: Size -> Operand r s -> First ((Bool, Size), CodeBuilder)     mkImmS = convertImm True     mkImm  = convertImm False     mkImmNo64 s = mkImmS (no64 s) -    xchg_a :: IsSize s => Operand s a -> CodeBuilder+    xchg_a :: IsSize s => Operand r s -> CodeBuilder     xchg_a dest@(RegOp r) | size dest /= S8 = regprefix (size dest) dest (oneReg 0x12 r) mempty     xchg_a dest = regprefix'' dest 0x43 (reg8 0x0 dest) mempty      toCode :: HasBytes a => a -> CodeBuilder     toCode = bytesToCodeBuilder . toBytes -    sizePrefix_ :: [SReg] -> Size -> Operand s a -> Word8 -> CodeBuilder -> CodeBuilder -> CodeBuilder+    sizePrefix_ :: [SReg] -> Size -> Operand r s -> Word8 -> CodeBuilder -> CodeBuilder -> CodeBuilder     sizePrefix_ rs s r x c im         | noHighRex rs = pre <> c <> displacement r <> im         | otherwise = error "cannot use high register in rex instruction"       where         pre = case s of-            S8  -> mem32pre r <> iff (any isRex rs || x /= 0) (prefix40_ x)+            S8  -> mem32pre r <> maybePrefix40             S16 -> codeByte 0x66 <> mem32pre r <> prefix40 x             S32 -> mem32pre r <> prefix40 x             S64 -> mem32pre r <> prefix40 (0x8 .|. x)+            S128 -> mem32pre r <> codeByte 0x66 <> maybePrefix40 -        mem32pre :: Operand s k -> CodeBuilder+        mem32pre :: Operand r s -> CodeBuilder         mem32pre (MemOp r@Addr{}) | size r == S32 = codeByte 0x67         mem32pre _ = mempty          prefix40 x = iff (x /= 0) $ prefix40_ x         prefix40_ x = codeByte $ 0x40 .|. x -        displacement :: Operand s a -> CodeBuilder-        displacement RegOp{} = mempty+        maybePrefix40 = iff (any isRex rs || x /= 0) (prefix40_ x)++        displacement :: Operand r s -> CodeBuilder         displacement (IPMemOp (Immediate d)) = toCode d         displacement (IPMemOp (LabelRelValue s@S32 d)) = mkRef s (sizeLen s + fromIntegral (codeBuilderLength im)) d         displacement (MemOp (Addr b d i)) = mkSIB b i <> dispVal b d@@ -348,80 +379,95 @@             dispVal Nothing _ = toCode (0 :: Int32)      -- [rbp] --> [rbp + 0]             dispVal (Just (reg8_ -> 0x5)) _ = codeByte 0      -- [rbp] --> [rbp + 0]             dispVal _ _ = mempty+        displacement _ = mempty      reg8_ :: Reg t -> Word8     reg8_ (NormalReg r) = r .&. 0x7     reg8_ (HighReg r) = r .|. 0x4+    reg8_ (XMM r) = r .&. 0x7 -    regprefix :: IsSize s => Size -> Operand s a -> CodeBuilder -> CodeBuilder -> CodeBuilder+    regprefix :: IsSize s => Size -> Operand r s -> CodeBuilder -> CodeBuilder -> CodeBuilder     regprefix s r c im = sizePrefix_ (regs r) s r (extbits r) c im -    regprefix2 :: (IsSize s1, IsSize s) => Operand s1 a1 -> Operand s a -> Word8 -> CodeBuilder -> CodeBuilder-    regprefix2 r r' p c = sizePrefix_ (regs r <> regs r') (size r) r (extbits r' `shiftL` 2 .|. extbits r) (extension r p <> c) mempty+    regprefix2 :: (IsSize s1, IsSize s) => Operand r1 s1 -> Operand r s -> CodeBuilder -> CodeBuilder+    regprefix2 r r' c = sizePrefix_ (regs r <> regs r') (size r) r (extbits r' `shiftL` 2 .|. extbits r) c mempty -    regprefix'' :: IsSize s => Operand s a -> Word8 -> CodeBuilder -> CodeBuilder -> CodeBuilder+    regprefix'' :: IsSize s => Operand r s -> Word8 -> CodeBuilder -> CodeBuilder -> CodeBuilder     regprefix'' r p c = regprefix (size r) r $ extension r p <> c +    regprefix2' :: (IsSize s1, IsSize s) => Operand r1 s1 -> Operand r s -> Word8 -> CodeBuilder -> CodeBuilder+    regprefix2' r r' p c = regprefix2 r r' $ extension r p <> c++    sse :: IsSize s => Word8 -> Operand r S128 -> Operand r' s -> CodeBuilder+    sse op a@OpXMM b = regprefix S128 b (codeByte 0x0f <> codeByte op <> reg2x8 a b) mempty++    sseShift :: Word8 -> Word8 -> Word8 -> Operand RW S128 -> Operand r S8 -> CodeBuilder+    sseShift op x op' a@OpXMM b@(mkImm S8 -> FJust (_, i)) = regprefix S128 b (codeByte 0x0f <> codeByte op <> reg8 x a) i+    -- TODO: xmm argument+     extension :: HasSize a => a -> Word8 -> CodeBuilder     extension x p = codeByte $ p `shiftL` 1 .|. indicator (size x /= S8) -    extbits :: Operand s a -> Word8+    extbits :: Operand r s -> Word8     extbits = \case         MemOp (Addr b _ i) -> maybe 0 indexReg b .|. maybe 0 ((`shiftL` 1) . indexReg . snd) i         RegOp r -> indexReg r-        IPMemOp{} -> 0+        _ -> 0       where         indexReg (NormalReg r) = r `shiftR` 3 .&. 1         indexReg _ = 0 -    reg8 :: Word8 -> Operand s a -> CodeBuilder+    reg8 :: Word8 -> Operand r s -> CodeBuilder     reg8 w x = codeByte $ operMode x `shiftL` 6 .|. w `shiftL` 3 .|. rc x       where-        operMode :: Operand s a -> Word8+        operMode :: Operand r s -> Word8         operMode (MemOp (Addr (Just (reg8_ -> 0x5)) NoDisp _)) = 0x1   -- [rbp] --> [rbp + 0]         operMode (MemOp (Addr Nothing _ _)) = 0x0         operMode (MemOp (Addr _ NoDisp _))  = 0x0         operMode (MemOp (Addr _ (Disp (Integral (_ :: Int8))) _))  = 0x1         operMode (MemOp (Addr _ Disp{} _))  = 0x2         operMode IPMemOp{}                  = 0x0-        operMode RegOp{}                    = 0x3+        operMode _                          = 0x3 -        rc :: Operand s a -> Word8+        rc :: Operand r s -> Word8         rc (MemOp (Addr (Just r) _ NoIndex)) = reg8_ r         rc MemOp{}   = 0x04      -- SIB byte         rc IPMemOp{} = 0x05         rc (RegOp r) = reg8_ r -    op2 :: IsSize s => Word8 -> Operand s RW -> Operand s k -> CodeBuilder+    op2 :: IsSize s => Word8 -> Operand RW s -> Operand r s -> CodeBuilder     op2 op dest@RegA src@(mkImmNo64 (size dest) -> FJust (_, im)) | size dest == S8 || isNothing (getFirst $ mkImmS S8 src)         = regprefix'' dest (op `shiftL` 2 .|. 0x2) mempty im     op2 op dest (mkImmS S8 <> mkImmNo64 (size dest) -> FJust ((_, k), im))         = regprefix'' dest (0x40 .|. indicator (size dest /= S8 && k == S8)) (reg8 op dest) im     op2 op dest src = op2' (op `shiftL` 2) dest $ noImm "1" src -    noImm :: String -> Operand s k -> Operand s RW+    noImm :: String -> Operand r s -> Operand RW s     noImm _ (RegOp r) = RegOp r     noImm _ (MemOp a) = MemOp a     noImm _ (IPMemOp a) = IPMemOp a     noImm er _ = error $ "immediate value of this size is not supported: " ++ er -    op2' :: IsSize s => Word8 -> Operand s RW -> Operand s RW -> CodeBuilder+    op2' :: IsSize s => Word8 -> Operand RW s -> Operand RW s -> CodeBuilder     op2' op dest src@RegOp{} = op2g op dest src     op2' op dest@RegOp{} src = op2g (op .|. 0x1) src dest -    op2g :: (IsSize t, IsSize s) => Word8 -> Operand s a1 -> Operand t a -> CodeBuilder-    op2g op dest src@(RegOp r) = regprefix2 dest src op $ reg8 (reg8_ r) dest+    op2g :: (IsSize t, IsSize s) => Word8 -> Operand r s -> Operand r' t -> CodeBuilder+    op2g op dest src = regprefix2' dest src op $ reg2x8 src dest -    op1_ :: IsSize s => Word8 -> Word8 -> Operand s a -> CodeBuilder -> CodeBuilder+    reg2x8 :: (IsSize s, IsSize s') => Operand r s -> Operand r' s' -> CodeBuilder+    reg2x8 (RegOp r) x = reg8 (reg8_ r) x++    op1_ :: IsSize s => Word8 -> Word8 -> Operand r s -> CodeBuilder -> CodeBuilder     op1_ r1 r2 dest im = regprefix'' dest r1 (reg8 r2 dest) im -    op1 :: IsSize s => Word8 -> Word8 -> Operand s a -> CodeBuilder+    op1 :: IsSize s => Word8 -> Word8 -> Operand r s -> CodeBuilder     op1 a b c = op1_ a b c mempty -    op1' :: Word8 -> Word8 -> Operand S64 RW -> CodeBuilder+    op1' :: Word8 -> Word8 -> Operand RW S64 -> CodeBuilder     op1' r1 r2 dest = regprefix S32 dest (codeByte r1 <> reg8 r2 dest) mempty -    shiftOp :: IsSize s => Word8 -> Operand s RW -> Operand S8 k -> CodeBuilder+    shiftOp :: IsSize s => Word8 -> Operand RW s -> Operand r S8 -> CodeBuilder     shiftOp c dest (ImmOp (Immediate 1)) = op1 0x68 c dest     shiftOp c dest (mkImm S8 -> FJust (_, i)) = op1_ 0x60 c dest i     shiftOp c dest RegCl = op1 0x69 c dest@@ -429,4 +475,101 @@      oneReg :: Word8 -> Reg t -> CodeBuilder     oneReg x r = codeByte $ x `shiftL` 3 .|. reg8_ r++pattern OpXMM <- RegOp XMM{}++-------------------------------------------------------------- asm codes++data Code where+    Scope       :: Code -> Code+    Up          :: Code -> Code+    EmptyCode   :: Code+    AppendCode  :: CodeBuilder -> Code -> Code -> Code+    CodeLine_   :: CodeBuilder -> CodeLine -> Code++instance Monoid Code where+    mempty  = EmptyCode+    mappend a b = AppendCode (mkCodeBuilder a <> mkCodeBuilder b) a b++pattern CodeLine x <- CodeLine_ _ x+  where CodeLine x =  CodeLine_ (mkCodeBuilder' x) x++pattern Ret = CodeLine Ret_+pattern Nop = CodeLine Nop_+pattern PushF = CodeLine PushF_+pattern PopF = CodeLine PopF_+pattern Cmc = CodeLine Cmc_+pattern Clc = CodeLine Clc_+pattern Stc = CodeLine Stc_+pattern Cli = CodeLine Cli_+pattern Sti = CodeLine Sti_+pattern Cld = CodeLine Cld_+pattern Std = CodeLine Std_+pattern Inc a = CodeLine (Inc_ a)+pattern Dec a = CodeLine (Dec_ a)+pattern Not a = CodeLine (Not_ a)+pattern Neg a = CodeLine (Neg_ a)+pattern Add a b = CodeLine (Add_ a b)+pattern Or  a b = CodeLine (Or_  a b)+pattern Adc a b = CodeLine (Adc_ a b)+pattern Sbb a b = CodeLine (Sbb_ a b)+pattern And a b = CodeLine (And_ a b)+pattern Sub a b = CodeLine (Sub_ a b)+pattern Xor a b = CodeLine (Xor_ a b)+pattern Cmp a b = CodeLine (Cmp_ a b)+pattern Test a b = CodeLine (Test_ a b)+pattern Mov a b = CodeLine (Mov_ a b)+pattern Cmov c a b = CodeLine (Cmov_ c a b)+pattern Rol a b = CodeLine (Rol_ a b)+pattern Ror a b = CodeLine (Ror_ a b)+pattern Rcl a b = CodeLine (Rcl_ a b)+pattern Rcr a b = CodeLine (Rcr_ a b)+pattern Shl a b = CodeLine (Shl_ a b)+pattern Shr a b = CodeLine (Shr_ a b)+pattern Sar a b = CodeLine (Sar_ a b)+pattern Xchg a b = CodeLine (Xchg_ a b)+pattern Movd   a b = CodeLine (Movd_   a b)+pattern Movq   a b = CodeLine (Movq_   a b)+pattern Movdqa a b = CodeLine (Movdqa_ a b)+pattern Paddb  a b = CodeLine (Paddb_  a b)+pattern Paddw  a b = CodeLine (Paddw_  a b)+pattern Paddd  a b = CodeLine (Paddd_  a b)+pattern Paddq  a b = CodeLine (Paddq_  a b)+pattern Psubb  a b = CodeLine (Psubb_  a b)+pattern Psubw  a b = CodeLine (Psubw_  a b)+pattern Psubd  a b = CodeLine (Psubd_  a b)+pattern Psubq  a b = CodeLine (Psubq_  a b)+pattern Pxor   a b = CodeLine (Pxor_   a b)+pattern Psllw  a b = CodeLine (Psllw_  a b)+pattern Pslld  a b = CodeLine (Pslld_  a b)+pattern Psllq  a b = CodeLine (Psllq_  a b)+pattern Pslldq a b = CodeLine (Pslldq_ a b)+pattern Psrlw  a b = CodeLine (Psrlw_  a b)+pattern Psrld  a b = CodeLine (Psrld_  a b)+pattern Psrlq  a b = CodeLine (Psrlq_  a b)+pattern Psrldq a b = CodeLine (Psrldq_ a b)+pattern Psraw  a b = CodeLine (Psraw_  a b)+pattern Psrad  a b = CodeLine (Psrad_  a b)+pattern Lea a b = CodeLine (Lea_ a b)+pattern J a b = CodeLine (J_ a b)+pattern Pop a = CodeLine (Pop_ a)+pattern Push a = CodeLine (Push_ a)+pattern Call a = CodeLine (Call_ a)+pattern Jmpq a = CodeLine (Jmpq_ a)+pattern Jmp a  = CodeLine (Jmp_  a)+pattern Data a = CodeLine (Data_ a)+pattern Align a = CodeLine (Align_ a)+pattern Label = CodeLine (Label_)++-------------++showCode = \case+    EmptyCode  -> return ()+    AppendCode _ a b -> showCode a >> showCode b++    Scope c -> get >>= \i -> put (i+1) >> local (i:) (showCode c)++    Up c -> local tail $ showCode c++    CodeLine x -> showCodeLine x 
CodeGen/X86/Examples.hs view
@@ -24,7 +24,7 @@     $  Mov rdi arg1
     <> Inc rdi
     <> Xor rdx rdx
-    <> Mov rax (imm 1)
+    <> Mov rax 1
     <> (Mov rcx rax <> Mov rax rdx <> Add rdx rcx <> Dec rdi) `j_back` NZ
 
 fibFun :: Word64 -> Word64
@@ -35,7 +35,7 @@     $  Mov rdi arg1
     <> Inc rdi
     <> Xor rdx rdx
-    <> Mov rax (imm 1)
+    <> Mov rax 1
     <> (Mov rcx rax <> Mov rax rdx <> Add rdx rcx <> traceReg "d" rax {- <> traceReg "d" rdi -} <> Dec rdi) `j_back` NZ
 
 tracedFibFun :: Word64 -> Word64
@@ -73,7 +73,7 @@     r <- mallocBytes 8                -- this is not required to be aligned (and in any case malloc aligns to machine words)
     pokeByteOff r 0 (v :: Word64)
     let code = saveNonVolatile 
-             $ Mov rdi arg1 <> Mov rax (addr $ base rdi)
+             $ Mov rdi arg1 <> Mov rax (addr rdi)
     return $ compile code r == v
 
 
CodeGen/X86/FFI.hs view
@@ -37,10 +37,19 @@ foreign import ccall "dynamic" callWord32           :: FunPtr Word32                -> Word32 foreign import ccall "dynamic" callWord16           :: FunPtr Word16                -> Word16 foreign import ccall "dynamic" callWord8            :: FunPtr Word8                 -> Word8+foreign import ccall "dynamic" callWord             :: FunPtr Word                  -> Word+foreign import ccall "dynamic" callInt64            :: FunPtr Int64                 -> Int64+foreign import ccall "dynamic" callInt32            :: FunPtr Int32                 -> Int32+foreign import ccall "dynamic" callInt16            :: FunPtr Int16                 -> Int16+foreign import ccall "dynamic" callInt8             :: FunPtr Int8                  -> Int8+foreign import ccall "dynamic" callInt              :: FunPtr Int                   -> Int foreign import ccall "dynamic" callBool             :: FunPtr Bool                  -> Bool foreign import ccall "dynamic" callIOUnit           :: FunPtr (IO ())               -> IO () foreign import ccall "dynamic" callWord64_Word64    :: FunPtr (Word64 -> Word64)    -> Word64 -> Word64 foreign import ccall "dynamic" callPtr_Word64       :: FunPtr (Ptr a -> Word64)     -> Ptr a -> Word64+foreign import ccall "dynamic" callPtr_Word         :: FunPtr (Ptr a -> Word)       -> Ptr a -> Word+foreign import ccall "dynamic" callPtr_Int64        :: FunPtr (Ptr a -> Int64)      -> Ptr a -> Int64+foreign import ccall "dynamic" callPtr_Int          :: FunPtr (Ptr a -> Int)        -> Ptr a -> Int  unsafeCallForeignPtr0 call p = unsafePerformIO $ evaluate (call (castPtrToFunPtr $ unsafeForeignPtrToPtr p)) <* touchForeignPtr p @@ -55,10 +64,19 @@ instance Callable Word32                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord32 instance Callable Word16                where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord16 instance Callable Word8                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord8+instance Callable Word                  where unsafeCallForeignPtr = unsafeCallForeignPtr0 callWord+instance Callable Int64                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callInt64+instance Callable Int32                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callInt32+instance Callable Int16                 where unsafeCallForeignPtr = unsafeCallForeignPtr0 callInt16+instance Callable Int8                  where unsafeCallForeignPtr = unsafeCallForeignPtr0 callInt8+instance Callable Int                   where unsafeCallForeignPtr = unsafeCallForeignPtr0 callInt instance Callable Bool                  where unsafeCallForeignPtr = unsafeCallForeignPtr0 callBool instance Callable (IO ())               where unsafeCallForeignPtr = unsafeCallForeignPtrIO0 callIOUnit instance Callable (Word64 -> Word64)    where unsafeCallForeignPtr = unsafeCallForeignPtr1 callWord64_Word64 instance Callable (Ptr a -> Word64)     where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Word64+instance Callable (Ptr a -> Word)       where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Word+instance Callable (Ptr a -> Int64)      where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Int64+instance Callable (Ptr a -> Int)        where unsafeCallForeignPtr = unsafeCallForeignPtr1 callPtr_Int  ------------------------------------------------------- 
CodeGen/X86/Tests.hs view
@@ -123,14 +123,14 @@ 
 genMems = MemOp <$> (arbitrary :: Gen (Addr S64))
 
-instance IsSize s => Arbitrary (Operand s RW) where
+instance IsSize s => Arbitrary (Operand RW s) where
     arbitrary = oneof
         [ genRegs
         , genMems
         , genIPBase
         ]
 
-instance IsSize s => Arbitrary (Operand s R) where
+instance IsSize s => Arbitrary (Operand R s) where
     arbitrary = oneof
         [ imm <$> oneof (arbVal <$> [S8, S16, S32, S64])
         , genRegs
@@ -159,42 +159,42 @@         , op2'' Mov
         ]
       where
-        op2 :: (forall s . IsSize s => Operand s RW -> Operand s R -> Code) -> Gen Code
+        op2 :: (forall s . IsSize s => Operand RW s -> Operand R s -> Code) -> Gen Code
         op2 op = oneof
-            [ f op (arbitrary :: Gen (Operand S8 RW))  arbitrary
-            , f op (arbitrary :: Gen (Operand S16 RW)) arbitrary
-            , f op (arbitrary :: Gen (Operand S32 RW)) arbitrary
-            , f op (arbitrary :: Gen (Operand S64 RW)) arbitrary
+            [ f op (arbitrary :: Gen (Operand RW S8))  arbitrary
+            , f op (arbitrary :: Gen (Operand RW S16)) arbitrary
+            , f op (arbitrary :: Gen (Operand RW S32)) arbitrary
+            , f op (arbitrary :: Gen (Operand RW S64)) arbitrary
             ]
           where
-            f :: forall s . IsSize s => (Operand s RW -> Operand s R -> Code) -> Gen (Operand s RW) -> Gen (Operand s R) -> Gen Code
+            f :: forall s . IsSize s => (Operand RW s -> Operand R s -> Code) -> Gen (Operand RW s) -> Gen (Operand R s) -> Gen Code
             f op a b = uncurry op <$> suchThat ((,) <$> a <*> b) (\(a, b) -> noHighRex (regs a <> regs b) && ok' a b && okk a b)
 
-        op2'' :: (forall s . IsSize s => Operand s RW -> Operand s R -> Code) -> Gen Code
+        op2'' :: (forall s . IsSize s => Operand RW s -> Operand R s -> Code) -> Gen Code
         op2'' op = oneof
-            [ f op (arbitrary :: Gen (Operand S8 RW))  arbitrary
-            , f op (arbitrary :: Gen (Operand S16 RW)) arbitrary
-            , f op (arbitrary :: Gen (Operand S32 RW)) arbitrary
-            , f op (arbitrary :: Gen (Operand S64 RW)) arbitrary
+            [ f op (arbitrary :: Gen (Operand RW S8))  arbitrary
+            , f op (arbitrary :: Gen (Operand RW S16)) arbitrary
+            , f op (arbitrary :: Gen (Operand RW S32)) arbitrary
+            , f op (arbitrary :: Gen (Operand RW S64)) arbitrary
             ]
           where
-            f :: forall s . IsSize s => (Operand s RW -> Operand s R -> Code) -> Gen (Operand s RW) -> Gen (Operand s R) -> Gen Code
+            f :: forall s . IsSize s => (Operand RW s -> Operand R s -> Code) -> Gen (Operand RW s) -> Gen (Operand R s) -> Gen Code
             f op a b = uncurry op <$> suchThat ((,) <$> a <*> b) (\(a, b) -> noHighRex (regs a <> regs b) && ok' a b && oki a b)
 
-        op2' :: (forall s . IsSize s => Operand s RW -> Operand S8 R -> Code) -> Gen Code
+        op2' :: (forall s . IsSize s => Operand RW s -> Operand R S8 -> Code) -> Gen Code
         op2' op = oneof
-            [ f op (arbitrary :: Gen (Operand S8 RW))  arb
-            , f op (arbitrary :: Gen (Operand S16 RW)) arb
-            , f op (arbitrary :: Gen (Operand S32 RW)) arb
-            , f op (arbitrary :: Gen (Operand S64 RW)) arb
+            [ f op (arbitrary :: Gen (Operand RW S8))  arb
+            , f op (arbitrary :: Gen (Operand RW S16)) arb
+            , f op (arbitrary :: Gen (Operand RW S32)) arb
+            , f op (arbitrary :: Gen (Operand RW S64)) arb
             ]
           where
             arb = oneof
-                [ imm . fromIntegral <$> (arbitrary :: Gen Word8)
+                [ imm <$> (arbitrary :: Gen Word8)
                 , return cl
                 ]
 
-            f :: forall s . IsSize s => (Operand s RW -> Operand S8 R -> Code) -> Gen (Operand s RW) -> Gen (Operand S8 R) -> Gen Code
+            f :: forall s . IsSize s => (Operand RW s -> Operand R S8 -> Code) -> Gen (Operand RW s) -> Gen (Operand R S8) -> Gen Code
             f op a b = uncurry op <$> suchThat ((,) <$> a <*> b) (\(a, b) -> noHighRex (regs a <> regs b) && ok' a b && okk a b && noteqreg a b)
 
         noteqreg a b = x == nub x where x = map phisicalReg $ regs a ++ regs b
@@ -271,13 +271,13 @@     arbitrary = do
         i <- arbitrary
         cF <- arbitrary
-        let   fff :: forall s s' r . (IsSize s, IsSize s') => Code -> (Operand s RW -> Operand s' r -> Code) -> Operand s RW -> Operand s' r -> Gen InstrTest
+        let   fff :: forall s s' r . (IsSize s, IsSize s') => Code -> (Operand RW s -> Operand r s' -> Code) -> Operand RW s -> Operand r s' -> Gen InstrTest
               fff op op' a b = do
                 let
                     (f1: f2: _) = map RegOp $ filter (`notElem` (regi a ++ regi b)) $ NormalReg <$> [8..15]
                     regi = map phisicalReg . regs
 
-                    ff :: Operand s RW -> Operand s' k -> Gen (Int64, Int64, Code -> Code)
+                    ff :: Operand RW s -> Operand k s' -> Gen (Int64, Int64, Code -> Code)
                     ff a@(RegOp x) (RegOp x') | Just Refl <- sizeEqCheck x x', x == x' = do
                         (av, inita) <- mkVal f2 a
                         return (av, av, inita)
@@ -315,8 +315,8 @@                     otest i x | isShift i = x
                     otest _ x = if_ (if oF' then O else NO) (Xor rax rax) x
 
-                    rcx' = resizeOperand rcx :: Operand s RW
-                    rdx' = resizeOperand rdx :: Operand s RW
+                    rcx' = resizeOperand rcx :: Operand RW s
+                    rdx' = resizeOperand rdx :: Operand RW s
                     sa = size a
 
                     ((cF', oF'), res) = case sa of
@@ -349,14 +349,14 @@             Mov a_ b_ -> fff i Mov a_ b_
 
       where
-        mkVal :: IsSize s => Operand S64 RW -> Operand s k -> Gen (Int64, Code -> Code)
+        mkVal :: IsSize s => Operand RW S64 -> Operand k s -> Gen (Int64, Code -> Code)
         mkVal _ o@(ImmOp (Immediate w)) = return (w, id)
         mkVal _ o@(RegOp x) = do
             v <- arbVal $ size o
             return (v, (Mov (RegOp x) (imm v) <>))
         mkVal helper x@(IPMemOp LabelRelValue{}) = do
             v <- arbVal $ size x
-            return (v, \c -> Scope $ Up Jmp {- <> align (size x) -} <:> Data (toBytes v) <.> c)
+            return (v, \c -> Scope $ Up jmp8 {- <> align (size x) -} <:> Data (toBytes v) <.> c)
         mkVal helper o@(MemOp (Addr (Just x) d i)) = do
             v <- arbVal $ size o
             (vi, setvi) <- case i of
@@ -368,7 +368,7 @@                 d' = (vi :: Int64) + case d of
                     NoDisp -> 0
                     Disp v -> fromIntegral v
-                rx = resizeOperand $ RegOp x :: Operand S64 RW
+                rx = resizeOperand $ RegOp x :: Operand RW S64
             return (v, ((leaData rx v <> Mov helper (imm d') <> Sub rx helper <> setvi) <>))
         mkVal helper o@(MemOp (Addr Nothing d (Just (sc, x)))) = do
             v <- arbVal $ size o
@@ -376,7 +376,7 @@                 d' = case d of
                     NoDisp -> 0 :: Int64
                     Disp v -> fromIntegral v
-                rx = resizeOperand $ RegOp x :: Operand S64 RW
+                rx = resizeOperand $ RegOp x :: Operand RW S64
             return (v, ((leaData rx v <> Mov helper (imm d') <> Sub rx helper) <>))
 
 
CodeGen/X86/Utils.hs view
@@ -14,6 +14,7 @@ import Debug.Trace
 
 import CodeGen.X86.Asm
+import CodeGen.X86.CodeGen
 import CodeGen.X86.CallConv
 
 -------------------------------------------------------------- derived constructs
@@ -25,30 +26,44 @@ 
 infixr 5 <:>, <.>
 
--- | short conditional forward jump (no auto size available for forward jumps)
-j = j8
+-- | auto size backward jump
+jmp_back = Jmp Nothing
 
+-- | auto size jump; the extra argument is the code between the jump and the label
+jmp x = if snd (bounds $ mkCodeBuilder x) <= 127 then jmp8 else jmp32
+
+-- | short jump
+jmp8 = Jmp $ Just S8
+
+-- | near jump
+jmp32 = Jmp $ Just S32
+
+-- | auto size conditional forward jump
+j c x = if snd (bounds $ mkCodeBuilder x) <= 127 then j8 c x else j32 c x
+
 -- | short conditional forward jump
-j8 c x = J (Just S8) c <> Up x <:> mempty
+j8 c x = J c (Just S8) <> Up x <:> mempty
 
 -- | near conditional forward jump
-j32 c x = J (Just S32) c <> Up x <:> mempty
+j32 c x = J c (Just S32) <> Up x <:> mempty
 
 -- | auto size conditional backward jump
-x `j_back` c = mempty <:> Up x <> J Nothing c
+x `j_back` c = mempty <:> Up x <> J c Nothing
 
 -- | short conditional backward jump
-x `j_back8` c = mempty <:> Up x <> J (Just S8) c
+x `j_back8` c = mempty <:> Up x <> J c (Just S8)
 
 -- | near conditional backward jump
-x `j_back32` c = mempty <:> Up x <> J (Just S32) c
+x `j_back32` c = mempty <:> Up x <> J c (Just S32)
 
-if_ c a b = (J (Just S8) c <> Up (Up a <> Jmp) <:> mempty) <> Up b <:> mempty
+if_ c a b = (J c (Just S8) <> Up (Up a <> jmp b) <:> mempty) <> Up b <:> mempty
 
-lea8 :: IsSize s => Operand s RW -> Operand S8 RW -> Code
+lea8 :: IsSize s => Operand RW s -> Operand RW S8 -> Code
 lea8 = Lea
 
-leaData r d = (lea8 r ipBase <> Up Jmp <:> mempty) <> Data (toBytes d) <:> mempty
+leaData r d = (lea8 r ipBase <> Up (jmp db) <:> mempty) <> db <:> mempty
+  where
+    db = Data (toBytes d)
 
 ------------------------------------------------------------------------------ 
 
@@ -57,8 +72,8 @@ ------------------------------------------------------------------------------ 
 -- * utils
 
-mov' :: forall s s' r . IsSize s' => Operand s RW -> Operand s' r -> Code
-mov' a b = Mov (resizeOperand a :: Operand s' RW) b
+mov' :: forall s s' r . IsSize s' => Operand RW s -> Operand r s' -> Code
+mov' a b = Mov (resizeOperand a :: Operand RW s') b
 
 newtype CString = CString String
 
@@ -66,13 +81,13 @@     toBytes (CString cs) = mconcat $ toBytes . (fromIntegral :: Int -> Word8) . fromEnum <$> (cs ++ "\0")
 
 -- | we should implement PUSHA and POPA later
-all_regs_except_rsp :: [Operand S64 rw]
+all_regs_except_rsp :: [Operand rw S64]
 all_regs_except_rsp = [ rax, rcx, rdx, rbx, {- rsp, -} rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 ]
 
 push_all = mconcat [ Push r | r <-         all_regs_except_rsp ]
 pop_all  = mconcat [ Pop  r | r <- reverse all_regs_except_rsp ]
 
-traceReg :: IsSize s => String -> Operand s RW -> Code
+traceReg :: IsSize s => String -> Operand RW s -> Code
 traceReg d r = 
        PushF <> push_all
     <> mov' arg2 r <> leaData arg1 (CString $ show r ++ " = %" ++ s ++ d ++ "\n") <> Xor rax rax <> callFun r11 printf
TODO.md view
@@ -11,6 +11,7 @@ -   codeBytes -> compile -   Bytes -> MachineCode ? -   Data -> DB+-   traceReg -> traceOp  # Documentation 
x86-64bit.cabal view
@@ -1,5 +1,5 @@ name:                x86-64bit
-version:             0.1.4
+version:             0.2
 homepage:            https://github.com/divipp/x86-64
 synopsis:            Runtime code generation for x86 64 bit machine code
 description:         The primary goal of x86-64bit is to provide a lightweight assembler for machine generated 64 bit x86 assembly instructions. See README.md for further details.