packages feed

x86-64bit 0.4.5 → 0.4.6

raw patch · 11 files changed

+1427/−1437 lines, 11 filesdep ~QuickCheckdep ~basedep ~vectorsetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: QuickCheck, base, vector

API changes (from Hackage documentation)

- CodeGen.X86: runTests :: IO ()
- CodeGen.X86.Examples: callCCode :: String -> Code
- CodeGen.X86.Examples: callCFun :: String -> IO ()
- CodeGen.X86.Examples: callHsCode :: CodeM ()
- CodeGen.X86.Examples: callHsFun :: Word64 -> Word64
- CodeGen.X86.Examples: callIO :: FunPtr (IO ()) -> IO ()
- CodeGen.X86.Examples: callPW :: FunPtr (Ptr a -> Word64) -> Ptr a -> Word64
- CodeGen.X86.Examples: callWW :: FunPtr (Word64 -> Word64) -> Word64 -> Word64
- CodeGen.X86.Examples: createPtrWord64_Word64 :: (Word64 -> Word64) -> IO (FunPtr (Word64 -> Word64))
- CodeGen.X86.Examples: fib :: Word64 -> Word64
- CodeGen.X86.Examples: fibCode :: Code
- CodeGen.X86.Examples: fibFun :: Word64 -> Word64
- CodeGen.X86.Examples: idCode :: CodeM ()
- CodeGen.X86.Examples: idFun :: Word64 -> Word64
- CodeGen.X86.Examples: instance CodeGen.X86.FFI.Callable (GHC.Ptr.Ptr a -> GHC.Word.Word64)
- CodeGen.X86.Examples: instance CodeGen.X86.FFI.Callable (GHC.Types.IO ())
- CodeGen.X86.Examples: instance CodeGen.X86.FFI.Callable (GHC.Word.Word64 -> GHC.Word.Word64)
- CodeGen.X86.Examples: instance CodeGen.X86.FFI.CallableHs (GHC.Word.Word64 -> GHC.Word.Word64)
- CodeGen.X86.Examples: memTestFun :: Word64 -> IO Bool
- CodeGen.X86.Examples: tracedFibCode :: Code
- CodeGen.X86.Examples: tracedFibFun :: Word64 -> Word64
+ CodeGen.X86: IndexReg :: Scale -> Reg s -> IndexReg s
+ CodeGen.X86: NoIndex :: IndexReg s
+ CodeGen.X86: pattern NLE :: () => () => Condition
+ CodeGen.X86: s1 :: Scale
+ CodeGen.X86: s2 :: Scale
+ CodeGen.X86: s4 :: Scale
+ CodeGen.X86: s8 :: Scale
- CodeGen.X86: call :: Operand r S64 -> Code
+ CodeGen.X86: call :: () => Operand r S64 -> Code
- CodeGen.X86: doWhile :: Condition -> CodeM a -> CodeM ()
+ CodeGen.X86: doWhile :: () => Condition -> CodeM a -> CodeM ()
- CodeGen.X86: if_ :: Condition -> CodeM a1 -> CodeM a -> CodeM ()
+ CodeGen.X86: if_ :: () => Condition -> CodeM a1 -> CodeM a2 -> CodeM ()
- CodeGen.X86: ipRelValue :: Label -> Operand R s
+ CodeGen.X86: ipRelValue :: () => Label -> Operand R s
- CodeGen.X86: jmpq :: Operand r S64 -> Code
+ CodeGen.X86: jmpq :: () => Operand r S64 -> Code
- CodeGen.X86: lea :: (IsSize s', IsSize s) => Operand RW s -> Operand RW s' -> Code
+ CodeGen.X86: lea :: (IsSize s, IsSize s') => Operand RW s -> Operand RW s' -> Code
- CodeGen.X86: leaData :: (HasBytes a, IsSize s) => Operand RW s -> a -> CodeM ()
+ CodeGen.X86: leaData :: (IsSize s, HasBytes a) => Operand RW s -> a -> CodeM ()
- CodeGen.X86: movd :: (IsSize s', IsSize s) => Operand RW s -> Operand r s' -> Code
+ CodeGen.X86: movd :: (IsSize s, IsSize s') => Operand RW s -> Operand r s' -> Code
- CodeGen.X86: movdqa :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: movdqa :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: movq :: (IsSize s', IsSize s) => Operand RW s -> Operand r s' -> Code
+ CodeGen.X86: movq :: (IsSize s, IsSize s') => Operand RW s -> Operand r s' -> Code
- CodeGen.X86: paddb :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: paddb :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: paddd :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: paddd :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: paddq :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: paddq :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: paddw :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: paddw :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: pslld :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: pslld :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: pslldq :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: pslldq :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psllq :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psllq :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psllw :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psllw :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psrad :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psrad :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psraw :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psraw :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psrld :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psrld :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psrldq :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psrldq :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psrlq :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psrlq :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psrlw :: Operand RW S128 -> Operand r S8 -> Code
+ CodeGen.X86: psrlw :: () => Operand RW S128 -> Operand r S8 -> Code
- CodeGen.X86: psubb :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: psubb :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: psubd :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: psubd :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: psubq :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: psubq :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: psubw :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: psubw :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: push :: Operand r S64 -> Code
+ CodeGen.X86: push :: () => Operand r S64 -> Code
- CodeGen.X86: pxor :: Operand RW S128 -> Operand r S128 -> Code
+ CodeGen.X86: pxor :: () => Operand RW S128 -> Operand r S128 -> Code
- CodeGen.X86: unless :: Condition -> CodeM a -> CodeM ()
+ CodeGen.X86: unless :: () => Condition -> CodeM a -> CodeM ()

Files

CodeGen/X86.hs view
@@ -25,7 +25,7 @@     -- ** SSE registers     , xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7     -- * Addresses-    , Addr (..), BaseReg, IndexReg, Scale, Displacement, Address+    , Addr (..), BaseReg, IndexReg (..), Scale, s1, s2, s4, s8, Displacement, Address     , addr     , addr8     , addr16@@ -158,8 +158,6 @@     , printf     , hsPtr     , CString (..)-    -- * Misc-    , runTests     ) where  import Data.Monoid@@ -169,5 +167,3 @@ import CodeGen.X86.FFI import CodeGen.X86.CallConv import CodeGen.X86.Utils-import CodeGen.X86.Tests-
CodeGen/X86/Asm.hs view
@@ -1,20 +1,21 @@-{-# language LambdaCase #-}-{-# language BangPatterns #-}-{-# language ViewPatterns #-}-{-# language PatternGuards #-}-{-# language PatternSynonyms #-}+{-# language GeneralizedNewtypeDeriving #-} {-# language NoMonomorphismRestriction #-} {-# language ScopedTypeVariables #-}-{-# language RankNTypes #-}+{-# language StandaloneDeriving #-}+{-# language FlexibleInstances #-}+{-# language FlexibleContexts #-}+{-# language PatternSynonyms #-}+{-# language KindSignatures #-}+{-# language PatternGuards #-}+{-# language BangPatterns #-}+{-# language ViewPatterns #-} {-# language TypeFamilies #-}-{-# language GADTs #-}+{-# language LambdaCase #-}+{-# language RankNTypes #-} {-# language DataKinds #-}-{-# language KindSignatures #-} {-# language PolyKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language StandaloneDeriving #-}+{-# language GADTs #-}+{-# language CPP #-} module CodeGen.X86.Asm where  import Numeric@@ -35,8 +36,7 @@  showNibble :: (Integral a, Bits a) => Int -> a -> Char showNibble n x = toEnum (b + if b < 10 then 48 else 87)-  where-    b = fromIntegral $ x `shiftR` (4*n) .&. 0x0f+  where b = fromIntegral $ x `shiftR` (4 * n) .&. 0x0f  showByte b = [showNibble 1 b, showNibble 0 b] @@ -50,30 +50,38 @@  class HasBytes a where toBytes :: a -> Bytes -instance HasBytes Word8  where toBytes w = [w]-instance HasBytes Word16 where toBytes w = [fromIntegral w, fromIntegral $ w `shiftR` 8]-instance HasBytes Word32 where toBytes w = [fromIntegral $ w `shiftR` n | n <- [0, 8.. 24]]-instance HasBytes Word64 where toBytes w = [fromIntegral $ w `shiftR` n | n <- [0, 8.. 56]]+instance HasBytes Word8  where+  toBytes w = [w]+instance HasBytes Word16 where+  toBytes w = [fromIntegral w, fromIntegral $ w `shiftR` 8]+instance HasBytes Word32 where+  toBytes w = [ fromIntegral $ w `shiftR` n | n <- [0, 8 .. 24] ]+instance HasBytes Word64 where+  toBytes w = [ fromIntegral $ w `shiftR` n | n <- [0, 8 .. 56] ] -instance HasBytes Int8  where toBytes w = toBytes (fromIntegral w :: Word8)-instance HasBytes Int16 where toBytes w = toBytes (fromIntegral w :: Word16)-instance HasBytes Int32 where toBytes w = toBytes (fromIntegral w :: Word32)-instance HasBytes Int64 where toBytes w = toBytes (fromIntegral w :: Word64)+instance HasBytes Int8  where+  toBytes w = toBytes (fromIntegral w :: Word8)+instance HasBytes Int16 where+  toBytes w = toBytes (fromIntegral w :: Word16)+instance HasBytes Int32 where+  toBytes w = toBytes (fromIntegral w :: Word32)+instance HasBytes Int64 where+  toBytes w = toBytes (fromIntegral w :: Word64)  ------------------------------------------------------- sizes  -- | The size of a register (in bits) data Size = S1 | S8 | S16 | S32 | S64 | S128-    deriving (Eq, Ord)+  deriving (Eq, Ord)  instance Show Size where-    show = \case-        S1   -> "bit"-        S8   -> "byte"-        S16  -> "word"-        S32  -> "dword"-        S64  -> "qword"-        S128 -> "oword"+  show = \case+    S1   -> "bit"+    S8   -> "byte"+    S16  -> "word"+    S32  -> "dword"+    S64  -> "qword"+    S128 -> "oword"  mkSize  1 = S8 mkSize  2 = S16@@ -82,11 +90,11 @@ mkSize 16 = S128  sizeLen = \case-    S8   ->  1-    S16  ->  2-    S32  ->  4-    S64  ->  8-    S128 -> 16+  S8   -> 1+  S16  -> 2+  S32  -> 4+  S64  -> 8+  S128 -> 16  class HasSize a where size :: a -> Size @@ -101,24 +109,24 @@  -- | Singleton type for size data SSize (s :: Size) where-    SSize1   :: SSize S1-    SSize8   :: SSize S8-    SSize16  :: SSize S16-    SSize32  :: SSize S32-    SSize64  :: SSize S64-    SSize128 :: SSize S128+  SSize1   :: SSize S1+  SSize8   :: SSize S8+  SSize16  :: SSize S16+  SSize32  :: SSize S32+  SSize64  :: SSize S64+  SSize128 :: SSize S128  instance HasSize (SSize s) where-    size = \case-        SSize1   -> S1-        SSize8   -> S8-        SSize16  -> S16-        SSize32  -> S32-        SSize64  -> S64-        SSize128 -> S128+  size = \case+    SSize1   -> S1+    SSize8   -> S8+    SSize16  -> S16+    SSize32  -> S32+    SSize64  -> S64+    SSize128 -> S128  class IsSize (s :: Size) where-    ssize :: SSize s+  ssize :: SSize s  instance IsSize S1   where ssize = SSize1 instance IsSize S8   where ssize = SSize8@@ -128,21 +136,21 @@ instance IsSize S128 where ssize = SSize128  data EqT s s' where-    Refl :: EqT s s+  Refl :: EqT s s  sizeEqCheck :: forall s s' f g . (IsSize s, IsSize s') => f s -> g s' -> Maybe (EqT s s') sizeEqCheck _ _ = case (ssize :: SSize s, ssize :: SSize s') of-    (SSize8 , SSize8)  -> Just Refl-    (SSize16, SSize16) -> Just Refl-    (SSize32, SSize32) -> Just Refl-    (SSize64, SSize64) -> Just Refl-    _ -> Nothing+  (SSize8 , SSize8)  -> Just Refl+  (SSize16, SSize16) -> Just Refl+  (SSize32, SSize32) -> Just Refl+  (SSize64, SSize64) -> Just Refl+  _ -> Nothing  ------------------------------------------------------- scale  -- | The scaling of an index. (replace with Size?) newtype Scale = Scale Word8-    deriving (Eq)+  deriving (Eq)  s1 = Scale 0x0 s2 = Scale 0x1@@ -150,25 +158,25 @@ s8 = Scale 0x3  toScale = \case-    1 -> s1-    2 -> s2-    4 -> s4-    8 -> s8+  1 -> s1+  2 -> s2+  4 -> s4+  8 -> s8  scaleFactor (Scale i) = case i of-    0x0 -> 1-    0x1 -> 2-    0x2 -> 4-    0x3 -> 8+  0x0 -> 1+  0x1 -> 2+  0x2 -> 4+  0x3 -> 8  ------------------------------------------------------- operand  -- | An operand can be an immediate, a register, a memory address or RIP-relative (memory address relative to the instruction pointer) 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+  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 :: IsSize s => Address s -> Operand rw s' addr = MemOp . makeAddr@@ -190,25 +198,25 @@ addr64 = addr  data Immediate a-    = Immediate a-    | LabelRelValue Size{-size hint-} Label+  = Immediate a+  | LabelRelValue Size{-size hint-} Label  -- Type of labels newtype Label = Label {unLabel :: Int}  instance Show Label where-    show (Label i) = ".l" ++ show i+  show (Label i) = ".l" ++ show i  -- | Operand access modes data Access-    = R     -- ^ readable operand-    | RW    -- ^ readable and writeable operand+  = R     -- ^ readable operand+  | RW    -- ^ readable and writeable operand  -- | A register. data Reg :: Size -> * where-    NormalReg :: Word8 -> Reg s      -- \"normal\" registers are for example @AL@, @BX@, @ECX@ or @RSI@-    HighReg   :: Word8 -> Reg S8     -- \"high\" registers are @AH@, @BH@, @CH@ etc-    XMM       :: Word8 -> Reg S128   -- XMM registers+  NormalReg :: Word8 -> Reg s      -- \"normal\" registers are for example @AL@, @BX@, @ECX@ or @RSI@+  HighReg   :: Word8 -> Reg S8     -- \"high\" registers are @AH@, @BH@, @CH@ etc+  XMM       :: Word8 -> Reg S128   -- XMM registers  deriving instance Eq (Reg s) deriving instance Ord (Reg s)@@ -217,15 +225,17 @@ -- For example in @[eax+4*ecx+20]@ the base register is @eax@, the displacement is @20@ and the -- index is @4*ecx@. data Addr s = Addr-    { baseReg        :: BaseReg s-    , displacement   :: Displacement-    , indexReg       :: IndexReg s-    }-    deriving (Eq)+  { baseReg        :: BaseReg s+  , displacement   :: Displacement+  , indexReg       :: IndexReg s+  }+  deriving (Eq) -type BaseReg s    = Maybe (Reg s)-data IndexReg s   = NoIndex | IndexReg Scale (Reg s)-    deriving (Eq)+type BaseReg s = Maybe (Reg s)++data IndexReg s = NoIndex | IndexReg Scale (Reg s)+  deriving (Eq)+ type Displacement = Maybe Int32  pattern NoDisp = Nothing@@ -242,89 +252,106 @@ ipRel8 = ipRel  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-          where-            r0 = ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"]-            r8 = ["r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"]-      where-        err = error $ "show @ RegOp" -- ++ show (s, i)+  show (XMM i) = "xmm" ++ show i+  show (HighReg i) =+    (["ah", " ch", "dh", "bh"] ++ repeat (error ("show @Reg")))+      !! fromIntegral i +  show r@(NormalReg i) =+    (!! fromIntegral i) . (++ repeat (error ("show @Reg"))) $ 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+   where+    r0 = ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"]+    r8 = ["r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"]+ instance IsSize s => Show (Addr s) where-    show (Addr b d i) = showSum $ shb b ++ shd d ++ shi i-      where-        shb Nothing = []-        shb (Just x) = [(True, show x)]-        shd NoDisp = []-        shd (Disp x) = [(signum x /= (-1), show (abs x))]-        shi NoIndex = []-        shi (IndexReg sc x) = [(True, show' (scaleFactor sc) ++ show x)]-        show' 1 = ""-        show' n = show n ++ " * "-        showSum [] = "0"-        showSum ((True, x): xs) = x ++ g xs-        showSum ((False, x): xs) = "-" ++ x ++ g xs-        g = concatMap (\(a, b) -> f a ++ b)-        f True = " + "-        f False = " - "+  show (Addr b d i) = showSum $ shb b ++ shd d ++ shi i+   where+    shb Nothing  = []+    shb (Just x) = [(True, show x)]+    shd NoDisp   = []+    shd (Disp x) = [(signum x /= (-1), show (abs x))]+    shi NoIndex         = []+    shi (IndexReg sc x) = [(True, show' (scaleFactor sc) ++ show x)]+    show' 1 = ""+    show' n = show n ++ " * "+    showSum []                = "0"+    showSum ((True , x) : xs) = x ++ g xs+    showSum ((False, x) : xs) = "-" ++ x ++ g xs+    g = concatMap (\(a, b) -> f a ++ b)+    f True  = " + "+    f False = " - "  instance IsSize s => Show (Operand a s) where-    show = \case-        ImmOp w -> show w-        RegOp r -> show r-        r@(MemOp a) -> show (size r) ++ " [" ++ show a ++ "]"-        r@(IPMemOp x) -> show (size r) ++ " [" ++ "rel " ++ show x ++ "]"-      where-        showp x | x < 0 = " - " ++ show (-x)-        showp x = " + " ++ show x+  show = \case+    ImmOp w       -> show w+    RegOp r       -> show r+    r@(MemOp   a) -> show (size r) ++ " [" ++ show a ++ "]"+    r@(IPMemOp x) -> show (size r) ++ " [" ++ "rel " ++ show x ++ "]"+   where+    showp x | x < 0 = " - " ++ show (-x)+    showp x         = " + " ++ show x  instance Show a => Show (Immediate a) where-    show (Immediate x) = show x-    show (LabelRelValue s x) = show x+  show (Immediate x) = show x+  show (LabelRelValue s x) = show x  instance IsSize s => HasSize (Operand a s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (Addr s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (Address s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (BaseReg s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (Reg s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance IsSize s => HasSize (IndexReg s) where-    size _ = size (ssize :: SSize s)+  size _ = size (ssize :: SSize s)  instance (rw ~ R) => Num (Operand rw s) where-    negate (ImmOp (Immediate x)) = ImmOp $ Immediate $ negate x-    fromInteger (Integral x) = ImmOp $ Immediate x-    fromInteger z = error $ show z ++ " does not fit into " -- ++ show s-    (+) = error "(+) @Operand"-    (-) = error "(-) @Operand"-    (*) = error "(*) @Operand"-    abs = error "abs @Operand"-    signum = error "signum @Operand"+  negate (ImmOp (Immediate x)) = ImmOp $ Immediate $ negate x+  fromInteger (Integral x) = ImmOp $ Immediate x+  fromInteger z = error $ show z ++ " does not fit into " -- ++ show s+  (+) = error "(+) @Operand"+  (-) = error "(-) @Operand"+  (*) = error "(*) @Operand"+  abs = error "abs @Operand"+  signum = error "signum @Operand" +#if MIN_VERSION_base(4,11,0)+instance Semigroup (Addr s) where+  Addr a b c <> Addr a' b' c' = Addr (getFirst $ First a <> First a') (getFirst $ First b <> First b') (c <> c')++instance Semigroup (IndexReg s) where+  i <> NoIndex = i+  NoIndex <> i = i+#endif+ instance Monoid (Addr s) where-    mempty = Addr (getFirst mempty) (getFirst mempty) mempty-    Addr a b c `mappend` Addr a' b' c' = Addr (getFirst $ First a <> First a') (getFirst $ First b <> First b') (c <> c')+  mempty = Addr (getFirst mempty) (getFirst mempty) mempty +#if !MIN_VERSION_base(4,11,0)+  Addr a b c `mappend` Addr a' b' c' = Addr (getFirst $ First a <> First a') (getFirst $ First b <> First b') (c <> c')+#endif+ instance Monoid (IndexReg s) where-    mempty = NoIndex-    i `mappend` NoIndex = i-    NoIndex `mappend` i = i+  mempty = NoIndex +#if !MIN_VERSION_base(4,11,0)+  i `mappend` NoIndex = i+  NoIndex `mappend` i = i+#endif+ base :: Reg s -> Addr s base x = Addr (Just x) NoDisp NoIndex @@ -341,31 +368,34 @@  disp :: (Bits a, Integral a) => a -> Addr s disp (Integral x)-    | x == 0 = mempty-    | otherwise = Addr Nothing (Disp x) NoIndex+  | x == 0 = mempty+  | otherwise = Addr Nothing (Disp x) NoIndex  data Address :: Size -> * where-    Address :: [(Int, Reg s)] -> Int -> Address s+  Address :: [(Int, Reg s)] -> Int -> Address s  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'-    abs = error "abs @Address"-    signum = error "signum @Address"+  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'++  abs    = error "abs @Address"+  signum = error "signum @Address"+ makeAddr :: Address s -> Addr s makeAddr (Address [(1, r)] d) = base r <> disp d makeAddr (Address [(t, r)] d) = index' t r <> disp d@@ -374,16 +404,16 @@ makeAddr (Address [(t, r'), (1, r)] d) = base r <> index' t r' <> disp d  class FromReg c where-    fromReg :: Reg s -> c s+  fromReg :: Reg s -> c s  instance FromReg Reg where-    fromReg = id+  fromReg = id  instance FromReg (Operand r) where-    fromReg = RegOp+  fromReg = RegOp  instance FromReg Address where-    fromReg r = Address [(1, r)] 0+  fromReg r = Address [(1, r)] 0  reg = fromReg . NormalReg @@ -526,23 +556,23 @@ pattern NLE = Condition 0xf  instance Show Condition where-    show (Condition x) = case x of-        0x0 -> "o"-        0x1 -> "no"-        0x2 -> "c"-        0x3 -> "nc"-        0x4 -> "z"-        0x5 -> "nz"-        0x6 -> "be"-        0x7 -> "nbe"-        0x8 -> "s"-        0x9 -> "ns"-        0xa -> "p"-        0xb -> "np"-        0xc -> "l"-        0xd -> "nl"-        0xe -> "le"-        0xf -> "nle"+  show (Condition x) = case x of+    0x0 -> "o"+    0x1 -> "no"+    0x2 -> "c"+    0x3 -> "nc"+    0x4 -> "z"+    0x5 -> "nz"+    0x6 -> "be"+    0x7 -> "nbe"+    0x8 -> "s"+    0x9 -> "ns"+    0xa -> "p"+    0xb -> "np"+    0xc -> "l"+    0xd -> "nl"+    0xe -> "le"+    0xf -> "nle"  pattern N cc <- (notCond -> cc)   where N = notCond@@ -552,42 +582,43 @@  -------------------------------------------------------------- asm code lines +{- HLINT ignore -} data CodeLine where-    Ret_, Nop_, PushF_, PopF_, Cmc_, Clc_, Stc_, Cli_, Sti_, Cld_, Std_   :: CodeLine+  Ret_, Nop_, PushF_, PopF_, Cmc_, Clc_, Stc_, Cli_, Sti_, Cld_, Std_ :: CodeLine -    Inc_, Dec_, Not_, Neg_, Bswap                               :: IsSize s => Operand RW s -> CodeLine-    Add_, Or_, Adc_, Sbb_, And_, Sub_, Xor_, Cmp_, Test_, Mov_, Bsf, Bsr :: 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-    Bt :: IsSize s => Operand r s -> Operand RW s -> CodeLine+  Inc_, Dec_, Not_, Neg_, Bswap                               :: IsSize s => Operand RW s -> CodeLine+  Add_, Or_, Adc_, Sbb_, And_, Sub_, Xor_, Cmp_, Test_, Mov_, Bsf, Bsr :: 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+  Bt :: IsSize s => Operand r s -> Operand RW s -> CodeLine -    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+  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 -    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+  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+  Pop_  :: Operand RW S64 -> CodeLine+  Push_ :: Operand r  S64 -> CodeLine -    Call_ :: Operand r S64 -> CodeLine-    Jmpq_ :: Operand r S64 -> CodeLine+  Call_ :: Operand r S64 -> CodeLine+  Jmpq_ :: Operand r S64 -> CodeLine -    J_    :: Condition -> Maybe Size -> Label -> CodeLine-    Jmp_  :: Maybe Size -> Label -> CodeLine+  J_    :: Condition -> Maybe Size -> Label -> CodeLine+  Jmp_  :: Maybe Size -> Label -> CodeLine -    Label_ :: CodeLine+  Label_ :: CodeLine -    Data_  :: Bytes -> CodeLine-    Align_ :: Int   -> CodeLine+  Data_  :: Bytes -> CodeLine+  Align_ :: Int   -> CodeLine  ------------------------- show code lines  newLabel = do-    i <- get-    put $ i + 1-    return $ Label i+  i <- get+  put $ i + 1+  return $ Label i  codeLine x = tell [x] @@ -598,80 +629,80 @@  showCodeLine :: CodeLine -> StateT Int (Writer [String]) () 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-    Bsf   op1 op2 -> showOp2 "bsf"  op1 op2-    Bsr   op1 op2 -> showOp2 "bsr"  op1 op2-    Bt    op1 op2 -> showOp2 "bt"   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-    Bswap op -> showOp1 "bswap" 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"+  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+  Bsf   op1 op2 -> showOp2 "bsf"  op1 op2+  Bsr   op1 op2 -> showOp2 "bsr"  op1 op2+  Bt    op1 op2 -> showOp2 "bt"   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+  Bswap op -> showOp1 "bswap" 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_ 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+  Align_ s -> codeLine $ ".align " ++ show s+  Data_ 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 -    J_ cc s l -> showOp ("j" ++ show cc) $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ show l-    Jmp_ s  l -> showOp "jmp" $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ show l-    Label_    -> newLabel >>= codeLine . show+  J_ cc s l -> showOp ("j" ++ show cc) $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ show l+  Jmp_ s  l -> showOp "jmp" $ (case s of Just S8 -> "short "; Just S32 -> "near "; _ -> "") ++ show l+  Label_    -> newLabel >>= codeLine . show 
CodeGen/X86/CallConv.hs view
@@ -2,7 +2,6 @@  {-# language NoMonomorphismRestriction #-} {-# language CPP #-}-{-# language BangPatterns #-} {-# language DataKinds #-} module CodeGen.X86.CallConv where @@ -19,33 +18,33 @@ -- On Win64 the caller have to reserve 32 byte "shadow space" on the stack (and clean up after) callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p = do-    sub rsp 32-    mov r (fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p)-    call r-    add rsp 32+  sub rsp 32+  mov r (fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p)+  call r+  add rsp 32  #elif defined (darwin_HOST_OS)  -- OSX requires 16 byte alignment of the stack... callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p = do-    push r15              -- we will use r15 (non-volatile) to store old rsp-    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 (fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p)-    call r-    mov rsp r15           -- restore rsp-    pop r15               -- restore r15+  push r15              -- we will use r15 (non-volatile) to store old rsp+  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 (fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p)+  call r+  mov rsp r15           -- restore rsp+  pop r15               -- restore r15  #else  -- helper to call a function callFun :: Operand RW S64 -> FunPtr a -> Code callFun r p = do-    mov r $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p-    call r+  mov r $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p+  call r  #endif @@ -91,16 +90,16 @@ result = rax  prologue = do-    push rbp-    push rbx-    push rdi-    push rsi+  push rbp+  push rbx+  push rdi+  push rsi  epilogue = do-    pop rsi-    pop rdi-    pop rbx-    pop rbp+  pop rsi+  pop rdi+  pop rbx+  pop rbp  #else @@ -117,12 +116,12 @@ result = rax  prologue = do-    push rbp-    push rbx+  push rbp+  push rbx  epilogue = do-    pop rbx-    pop rbp+  pop rbx+  pop rbp  #endif 
CodeGen/X86/CodeGen.hs view
@@ -1,20 +1,18 @@-{-# language LambdaCase #-}-{-# language BangPatterns #-}-{-# language ViewPatterns #-}-{-# language PatternGuards #-}-{-# language PatternSynonyms #-}+{-# language GeneralizedNewtypeDeriving #-} {-# language NoMonomorphismRestriction #-} {-# language ScopedTypeVariables #-}-{-# language RankNTypes #-}+{-# language FlexibleInstances #-}+{-# language FlexibleContexts #-}+{-# language PatternSynonyms #-}+{-# language ViewPatterns #-} {-# language TypeFamilies #-}-{-# language GADTs #-}+{-# language RecursiveDo #-}+{-# language LambdaCase #-}+{-# language RankNTypes #-} {-# language DataKinds #-}-{-# language KindSignatures #-} {-# language PolyKinds #-}-{-# language FlexibleContexts #-}-{-# language FlexibleInstances #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language RecursiveDo #-}+{-# language GADTs #-}+{-# language CPP #-} module CodeGen.X86.CodeGen where  import Numeric@@ -60,7 +58,7 @@ ------------------------------------------------------- register packed with its size  data SReg where-    SReg :: IsSize s => Reg s -> SReg+  SReg :: IsSize s => Reg s -> SReg  phisicalReg :: SReg -> Reg S64 phisicalReg (SReg (HighReg x)) = NormalReg x@@ -71,9 +69,9 @@  regs :: IsSize s => Operand r s -> [SReg] regs = \case-    MemOp (Addr r _ i) -> foldMap (pure . SReg) r ++ case i of NoIndex -> []; IndexReg _ x -> [SReg x]-    RegOp r -> [SReg r]-    _ -> mempty+  MemOp (Addr r _ i) -> foldMap (pure . SReg) r ++ case i of NoIndex -> []; IndexReg _ x -> [SReg x]+  RegOp r -> [SReg r]+  _ -> mempty  isRex (SReg x@(NormalReg r)) = r .&. 0x8 /= 0 || size x == S8 && r `shiftR` 2 == 1 isRex _ = False@@ -90,120 +88,131 @@ type CodeBuilderTardis = Tardis (Int, [Int]) (Int, [Int], LabelState)  data CodeBuilder = CodeBuilder-    { minLen, maxLen :: Int-    , getCodeBuilder :: WriterT CodeBuilderRes CodeBuilderTardis ()-    }+  { minLen, maxLen :: Int+  , getCodeBuilder :: WriterT CodeBuilderRes CodeBuilderTardis ()+  }  codeBuilderLength (CodeBuilder a b _) | a == b = a  type LabelState = [[(Size, Int, Int)]] +#if MIN_VERSION_base(4,11,0)+instance Semigroup CodeBuilder where+  CodeBuilder mi ma a <> CodeBuilder mi' ma' b = CodeBuilder (min mi mi') (max ma ma') $ a >> b+#endif+ instance Monoid CodeBuilder where-    mempty = CodeBuilder 0 0 $ return ()-    CodeBuilder mi ma a `mappend` CodeBuilder mi' ma' b = CodeBuilder (min mi mi') (max ma ma') $ a >> b+  mempty = CodeBuilder 0 0 $ return ()+#if !MIN_VERSION_base(4,11,0)+  CodeBuilder mi ma a `mappend` CodeBuilder mi' ma' b = CodeBuilder (min mi mi') (max ma ma') $ a >> b+#endif  codeBytes :: [Word8] -> CodeBuilder codeBytes bs = CodeBuilder n n $ do-    c <- lift $ mdo-        (c, ls, ps) <- getPast-        sendFuture (c + n, ls, ps)-        sendPast (ma + n, mls)-        ~(ma, mls) <- getFuture-        return c-    tell $ Right <$> zip [c..] bs+  c <- lift $ mdo+    (c, ls, ps) <- getPast+    sendFuture (c + n, ls, ps)+    sendPast (ma + n, mls)+    ~(ma, mls) <- getFuture+    return c+  tell $ Right <$> zip [c..] bs   where-    n = length bs+  n = length bs  codeByte :: Word8 -> CodeBuilder codeByte = codeBytes . (:[])  mkRef :: Size -> Int -> Label -> CodeBuilder mkRef s@(sizeLen -> sn) offset (Label l_) = CodeBuilder sn sn $ do-    bs <- lift $ mdo-        (n, ls, ps) <- getPast-        sendFuture (n + sn, ls, ps')-        sendPast (ma + sn, mls)-        ~(ma, mls) <- getFuture-        let i = ls !! (- l - 1)-            vx = i - n - offset-            z = case s of-                S8  -> case vx of-                    Integral j -> toBytes (j :: Int8)-                    _ -> error $ show vx ++ " does not fit into an Int8"-                S32  -> case vx of-                    Integral j -> toBytes (j :: Int32)-                    _ -> error $ show vx ++ " does not fit into an Int32"-            ~(bs, ps')-                | l < 0 = (z, ps)-                | otherwise = ([], ins l (s, n, - n - offset) ps)-            l = l_ - length ls-        return $ zip [n..] bs-    tell $ Right <$> bs+  bs <- lift $ mdo+    (n, ls, ps) <- getPast+    sendFuture (n + sn, ls, ps')+    sendPast (ma + sn, mls)+    ~(ma, mls) <- getFuture+    let i = ls !! (- l - 1)+        vx = i - n - offset+        z = case s of+          S8  -> case vx of+            Integral j -> toBytes (j :: Int8)+            _ -> error $ show vx ++ " does not fit into an Int8"+          S32  -> case vx of+            Integral j -> toBytes (j :: Int32)+            _ -> error $ show vx ++ " does not fit into an Int32"+        ~(bs, ps')+          | l < 0 = (z, ps)+          | otherwise = ([], ins l (s, n, - n - offset) ps)+        l = l_ - length ls+    return $ zip [n..] bs+  tell $ Right <$> bs  ins :: Int -> a -> [[a]] -> [[a]]-ins 0 a [] = [a]: []+ins 0 a [] = [[a]] ins 0 a (as:ass) = (a:as): ass ins n a [] = []: ins (n-1) a [] ins n a (as: ass) = as: ins (n-1) a ass  mkAutoRef :: [(Size, Bytes)] -> Label -> CodeBuilder mkAutoRef ss (Label l_) = CodeBuilder (minimum sizes) (maximum sizes) $ do-    bs <- lift $ mdo-        (n, ls, ps) <- getPast-        sendFuture (n + sn, ls, ps')-        sendPast (ma + maximum sizes, mls)-        ~(ma, mls) <- getFuture-        let i = ls !! (- l - 1)-            vx = i - n-            z = g ss-            g [] = error $ show vx ++ " does not fit into auto size"-            g ((s, c): ss) = case (s, vx - length c - sizeLen s) of-                (S8,  Integral j) -> c <> toBytes (j :: Int8)-                (S32, Integral j) -> c <> toBytes (j :: Int32)-                _ -> g ss-            ~(sn, bs, ps')-                | l < 0 = (length z, z, ps)-                | otherwise = (nz, z', ins l (s, n + length z', - n - nz) ps)-            nz = length z' + sizeLen s-            ma' = mls !! l-            vx' = ma - ma'-            (z', s) = g' ss-            g' [] = error $ show vx' ++ " does not fit into auto size"-            g' ((s, c): ss) = case (s, vx') of-                (S8,  Integral (j :: Int8)) -> (c, s)-                (S32, Integral (j :: Int32)) -> (c, s)-                _ -> g' ss-            l = l_ - length ls-        return $ zip [n..] bs-    tell $ Right <$> bs+  bs <- lift $ mdo+    (n, ls, ps) <- getPast+    sendFuture (n + sn, ls, ps')+    sendPast (ma + maximum sizes, mls)+    ~(ma, mls) <- getFuture+    let i = ls !! (- l - 1)+        vx = i - n+        z = g ss++        g [] = error $ show vx ++ " does not fit into auto size"+        g ((s, c): ss) = case (s, vx - length c - sizeLen s) of+          (S8,  Integral j) -> c <> toBytes (j :: Int8)+          (S32, Integral j) -> c <> toBytes (j :: Int32)+          _ -> g ss++        ~(sn, bs, ps')+          | l < 0 = (length z, z, ps)+          | otherwise = (nz, z', ins l (s, n + length z', - n - nz) ps)++        nz = length z' + sizeLen s+        ma' = mls !! l+        vx' = ma - ma'+        (z', s) = g' ss++        g' [] = error $ show vx' ++ " does not fit into auto size"+        g' ((s, c): ss) = case (s, vx') of+          (S8,  Integral (j :: Int8)) -> (c, s)+          (S32, Integral (j :: Int32)) -> (c, s)+          _ -> g' ss++        l = l_ - length ls+    return $ zip [n..] bs+  tell $ Right <$> bs   where-    sizes = map (\(s, c) -> sizeLen s + length c) ss+  sizes = map (\(s, c) -> sizeLen s + length c) ss  -- prebuild code preBuild :: Code -> Code preBuild c = CodeM $ tell $ Prebuilt (compactCode (buildCode lc)) lc   where-    lc = withLabels c+  lc = withLabels c  ------------------------------------------------------- code to code builder  instance Show Code where-    show = show . withLabels+  show = show . withLabels  instance Show LCode where-    show c = unlines $ zipWith3 showLine is (takes (zipWith (-) (tail is ++ [s]) is) bs) ss-      where-        ss = snd . runWriter . flip evalStateT 0 . showCode $ c-        (x, s) = buildCode c-        bs = V.toList $ compactCode (x, s)-        is = [i | Left i <- x]+  show c = unlines $ zipWith3 showLine is (takes (zipWith (-) (tail is ++ [s]) is) bs) ss where+    ss = snd . runWriter . flip evalStateT 0 . showCode $ c+    (x, s) = buildCode c+    bs = V.toList $ compactCode (x, s)+    is = [i | Left i <- x] -        showLine addr [] s = s-        showLine addr bs s = [showNibble i addr | i <- [5,4..0]] ++ " " ++ pad (2 * maxbytes) (concatMap showByte bs) ++ " " ++ s+    showLine addr [] s = s+    showLine addr bs s = [showNibble i addr | i <- [5,4..0]] ++ " " ++ pad (2 * maxbytes) (concatMap showByte bs) ++ " " ++ s -        pad i xs = xs ++ replicate (i - length xs) ' '+    pad i xs = xs ++ replicate (i - length xs) ' ' -        maxbytes = 12+    maxbytes = 12  compactCode :: (CodeBuilderRes, Int) -> V.Vector Word8 compactCode (x, s) = V.replicate s 0 V.// [p | Right p <- x]@@ -214,390 +223,395 @@ buildCode :: LCode -> (CodeBuilderRes, Int) buildCode x = (r, len)   where-    ((_, r), (_, (len, _, _))) = flip runTardis ((0, []), (0, [], [])) . runWriterT . getCodeBuilder . mkCodeBuilder $ x+  ((_, r), (_, (len, _, _))) = flip runTardis ((0, []), (0, [], [])) . runWriterT . getCodeBuilder . mkCodeBuilder $ x  mkCodeBuilder :: LCode -> CodeBuilder mkCodeBuilder = \case-    CodeLine x _ -> x-    Prebuilt v _ -> mkCodeBuilder' (Align_ 4) <> codeBytes (V.toList v)-    AppendCode x _ _ -> x-    EmptyCode -> mempty+  CodeLine x _ -> x+  Prebuilt v _ -> mkCodeBuilder' (Align_ 4) <> codeBytes (V.toList v)+  AppendCode x _ _ -> x+  EmptyCode -> mempty  newtype CodeM a = CodeM {unCodeM :: StateT Int (Writer LCode) a}-    deriving (Functor, Applicative, Monad, MonadFix)+  deriving (Functor, Applicative, Monad, MonadFix)  type Code = CodeM ()  withLabels :: Code -> LCode withLabels =-    snd . runWriter . flip evalStateT 0 . unCodeM+  snd . runWriter . flip evalStateT 0 . unCodeM  -- multi-byte nop operations nops :: Int -> Bytes nops = \case-    0 -> []-    1 -> [0x90]-    2 -> [0x66, 0x90]-    3 -> [0x0f, 0x1f, 0x00]-    4 -> [0x0f, 0x1f, 0x40, 0x00]-    5 -> [0x0f, 0x1f, 0x44, 0x00, 0x00]-    6 -> [0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00]-    7 -> [0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00]-    8 -> [0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]-    9 -> [0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]-    ((+(-2)) -> Integral x) -> [0xeb] ++ toBytes (x :: Int8) ++ replicate (fromIntegral x) 0x00-    ((+(-5)) -> Integral x) -> [0xe9] ++ toBytes (x :: Int32) ++ replicate (fromIntegral x) 0x00+  0 -> []+  1 -> [0x90]+  2 -> [0x66, 0x90]+  3 -> [0x0f, 0x1f, 0x00]+  4 -> [0x0f, 0x1f, 0x40, 0x00]+  5 -> [0x0f, 0x1f, 0x44, 0x00, 0x00]+  6 -> [0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00]+  7 -> [0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00]+  8 -> [0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]+  9 -> [0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]+  ((+(-2)) -> Integral x) -> [0xeb] ++ toBytes (x :: Int8) ++ replicate (fromIntegral x) 0x00+  ((+(-5)) -> Integral x) -> [0xe9] ++ toBytes (x :: Int32) ++ replicate (fromIntegral x) 0x00  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-      where-        (dest', src') = if isMemOp src then (src, dest) else (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-        RegA -> regprefix'' dest 0x54 mempty im-        _ -> regprefix'' dest 0x7b (reg8 0x0 dest) im-    Test_ dest (noImm "" -> src) -> op2' 0x42 dest' src'-      where-        (dest', src') = if isMemOp src then (src, dest) else (dest, src)+  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' where+    (dest', src') = if isMemOp src then (src, dest) else (dest, src) -    Mov_ dest@(RegOp r) ((if size dest == S64 then mkImmU S32 <> mkImm S64 else mkImm (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@(RegOp r) ((if size dest == S64 then mkImmU S32 <> mkImm S64 else mkImm (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 -    Cmov_ (Condition c) dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte (0x40 .|. c) <> reg2x8 dest src-    Bsf dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xbc <> reg2x8 dest src-    Bsr dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xbd <> reg2x8 dest src-    Bt  src dest | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xa3 <> reg2x8 dest src+  Cmov_ (Condition c) dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte (0x40 .|. c) <> reg2x8 dest src+  Bsf dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xbc <> reg2x8 dest src+  Bsr dest src | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xbd <> reg2x8 dest src+  Bt  src dest | size dest /= S8 -> regprefix2 src dest $ codeByte 0x0f <> codeByte 0xa3 <> reg2x8 dest src -    Lea_ dest src | size dest /= S8 -> regprefix2' (resizeOperand' dest src) dest 0x46 $ reg2x8 dest src-      where-        resizeOperand' :: IsSize s1 => Operand x s1 -> Operand RW s2 -> Operand RW s1-        resizeOperand' _ = resizeOperand+  Lea_ dest src | size dest /= S8 -> regprefix2' (resizeOperand' dest src) dest 0x46 $ reg2x8 dest src where+    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-    Bswap a@RegOp{} | size a >= S32 -> op1 0x07 0x1 a-    Bswap a  -> error $ "wrong bswap operand: " ++ show 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+  Bswap a@RegOp{} | size a >= S32 -> op1 0x07 0x1 a+  Bswap a  -> error $ "wrong bswap operand: " ++ show a -    Call_ (ImmOp (LabelRelValue S32 l)) -> codeByte 0xe8 <> mkRef S32 4 l-    Call_ a -> op1' 0xff 0x2 a+  Call_ (ImmOp (LabelRelValue S32 l)) -> codeByte 0xe8 <> mkRef S32 4 l+  Call_ a -> op1' 0xff 0x2 a -    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+  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 -    Pop_ dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0b r) mempty-    Pop_ dest -> regprefix S32 dest (codeByte 0x8f <> reg8 0x0 dest) mempty+  Pop_ dest@(RegOp r) -> regprefix S32 dest (oneReg 0x0b r) mempty+  Pop_ dest -> regprefix S32 dest (codeByte 0x8f <> reg8 0x0 dest) mempty -    Push_ (mkImmS S8 -> FJust (_, im)) -> codeByte 0x6a <> im-    Push_ (mkImm 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+  Push_ (mkImmS S8 -> FJust (_, im)) -> codeByte 0x6a <> im+  Push_ (mkImm 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 -    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+  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 -    J_ (Condition c) (Just S8)  l -> codeByte (0x70 .|. c) <> mkRef S8 1 l-    J_ (Condition c) (Just S32) l -> codeByte 0x0f <> codeByte (0x80 .|. c) <> mkRef S32 4 l-    J_ (Condition c) Nothing    l -> mkAutoRef [(S8, [0x70 .|. c]), (S32, [0x0f, 0x80 .|. c])] l+  J_ (Condition c) (Just S8)  l -> codeByte (0x70 .|. c) <> mkRef S8 1 l+  J_ (Condition c) (Just S32) l -> codeByte 0x0f <> codeByte (0x80 .|. c) <> mkRef S32 4 l+  J_ (Condition c) Nothing  l -> mkAutoRef [(S8, [0x70 .|. c]), (S32, [0x0f, 0x80 .|. c])] l -    Jmp_ (Just S8)  l -> codeByte 0xeb <> mkRef S8 1 l-    Jmp_ (Just S32) l -> codeByte 0xe9 <> mkRef S32 4 l-    Jmp_ Nothing    l -> mkAutoRef [(S8, [0xeb]), (S32, [0xe9])] l+  Jmp_ (Just S8)  l -> codeByte 0xeb <> mkRef S8 1 l+  Jmp_ (Just S32) l -> codeByte 0xe9 <> mkRef S32 4 l+  Jmp_ Nothing  l -> mkAutoRef [(S8, [0xeb]), (S32, [0xe9])] l -    Jmpq_ (ImmOp (LabelRelValue S32 l)) -> mkAutoRef [(S8, [0xeb]), (S32, [0xe9])] l-    Jmpq_ a -> op1' 0xff 0x4 a+  Jmpq_ (ImmOp (LabelRelValue S32 l)) -> mkAutoRef [(S8, [0xeb]), (S32, [0xe9])] l+  Jmpq_ a -> op1' 0xff 0x4 a -    Label_ -> CodeBuilder 0 0 $ do-        bs <- lift $ mdo-            (n, ls, ps) <- getPast-            sendFuture (n, n: ls, ps')-            sendPast (ma, ma: mls)-            ~(ma, mls) <- getFuture-            let (bs, ps') = case ps of-                    [] -> ([], [])-                    corr: ps -> (concatMap g corr, ps)-                g (size, p, v) = zip [p..] $ 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-            return bs-        tell $ Right <$> bs+  Label_ -> CodeBuilder 0 0 $ do+    bs <- lift $ mdo+      (n, ls, ps) <- getPast+      sendFuture (n, n: ls, ps')+      sendPast (ma, ma: mls)+      ~(ma, mls) <- getFuture+      let (bs, ps') = case ps of+            [] -> ([], [])+            corr: ps -> (concatMap g corr, ps)+          g (size, p, v) = zip [p..] $ 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+      return bs+    tell $ Right <$> bs  -    Data_ x -> codeBytes x+  Data_ x -> codeBytes x -    Align_ s -> CodeBuilder 0 (s-1) $ do-        bs <- lift $ mdo-            (n, ls, ps) <- getPast-            sendFuture (n', ls, ps)-            sendPast (ma + s-1, mls)-            ~(ma, mls) <- getFuture-            let n' = fromIntegral $ ((fromIntegral n - 1 :: Int64) .|. (fromIntegral s - 1)) + 1-            return $ zip [n..] $ nops $ n' - n-        tell $ Right <$> bs+  Align_ s -> CodeBuilder 0 (s-1) $ do+    bs <- lift $ mdo+      (n, ls, ps) <- getPast+      sendFuture (n', ls, ps)+      sendPast (ma + s-1, mls)+      ~(ma, mls) <- getFuture+      let n' = fromIntegral $ ((fromIntegral n - 1 :: Int64) .|. (fromIntegral s - 1)) + 1+      return $ zip [n..] $ nops $ n' - n+    tell $ Right <$> bs    where-    convertImm :: Bool{-signed-} -> Size -> Operand r s -> First ((Bool, Size), CodeBuilder)-    convertImm a b (ImmOp (Immediate c)) = First $ (,) (a, b) . codeBytes <$> integralToBytes a b c-    convertImm True b (ImmOp (LabelRelValue s d)) | b == s = FJust $ (,) (True, b) $ mkRef s (sizeLen s) d-    convertImm _ _ _ = FNothing+  convertImm :: Bool{-signed-} -> Size -> Operand r s -> First ((Bool, Size), CodeBuilder)+  convertImm a b (ImmOp (Immediate c)) = First $ (,) (a, b) . codeBytes <$> integralToBytes a b c+  convertImm True b (ImmOp (LabelRelValue s d)) | b == s = FJust $ (,) (True, b) $ mkRef s (sizeLen s) d+  convertImm _ _ _ = FNothing -    mkImmS, mkImmU, mkImm, mkImmNo64 :: Size -> Operand r s -> First ((Bool, Size), CodeBuilder)-    mkImmS = convertImm True-    mkImmU = convertImm False-    mkImm s = mkImmS s <> mkImmU s-    mkImmNo64 s = mkImm (no64 s)+  mkImmS, mkImmU, mkImm, mkImmNo64 :: Size -> Operand r s -> First ((Bool, Size), CodeBuilder)+  mkImmS = convertImm True+  mkImmU = convertImm False+  mkImm s = mkImmS s <> mkImmU s+  mkImmNo64 s = mkImm (no64 s) -    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+  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 = codeBytes . toBytes+  toCode :: HasBytes a => a -> CodeBuilder+  toCode = codeBytes . toBytes -    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 <> 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+  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 <> 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 r s -> CodeBuilder-        mem32pre (MemOp r@Addr{}) | size r == S32 = codeByte 0x67-        mem32pre _ = mempty+      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+      prefix40 x = iff (x /= 0) $ prefix40_ x+      prefix40_ x = codeByte $ 0x40 .|. x -        maybePrefix40 = iff (any isRex rs || x /= 0) (prefix40_ x)+      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-          where-            mkSIB _ (IndexReg s (NormalReg 0x4)) = error "sp cannot be used as index"-            mkSIB _ (IndexReg s i) = f s $ reg8_ i-            mkSIB Nothing _ = f s1 0x4-            mkSIB (Just (reg8_ -> 0x4)) _ = f s1 0x4-            mkSIB _ _ = mempty+      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+        where+          mkSIB _ (IndexReg s (NormalReg 0x4)) = error "sp cannot be used as index"+          mkSIB _ (IndexReg s i) = f s $ reg8_ i+          mkSIB Nothing _ = f s1 0x4+          mkSIB (Just (reg8_ -> 0x4)) _ = f s1 0x4+          mkSIB _ _ = mempty -            f (Scale s) i = codeByte $ s `shiftL` 6 .|. i `shiftL` 3 .|. maybe 0x5 reg8_ b+          f (Scale s) i = codeByte $ s `shiftL` 6 .|. i `shiftL` 3 .|. maybe 0x5 reg8_ b -            dispVal Just{} (Disp (Integral (d :: Int8))) = toCode d-            dispVal _ (Disp d) = toCode d-            dispVal Nothing _ = toCode (0 :: Int32)      -- [rbp] --> [rbp + 0]-            dispVal (Just (reg8_ -> 0x5)) _ = codeByte 0      -- [rbp] --> [rbp + 0]-            dispVal _ _ = mempty-        displacement _ = mempty+          dispVal Just{} (Disp (Integral (d :: Int8))) = toCode d+          dispVal _ (Disp d) = toCode d+          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+  reg8_ :: Reg t -> Word8+  reg8_ (NormalReg r) = r .&. 0x7+  reg8_ (HighReg r) = r .|. 0x4+  reg8_ (XMM r) = r .&. 0x7 -    regprefix :: IsSize s => Size -> Operand r s -> CodeBuilder -> CodeBuilder -> CodeBuilder-    regprefix s r c im = sizePrefix_ (regs r) s r (extbits r) c im+  regprefix :: IsSize s => Size -> Operand r s -> CodeBuilder -> CodeBuilder -> CodeBuilder+  regprefix s r = sizePrefix_ (regs r) s r (extbits r) -    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+  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 r s -> Word8 -> CodeBuilder -> CodeBuilder -> CodeBuilder-    regprefix'' r p c = regprefix (size r) r $ extension r p <> c+  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+  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+  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@(mkImmU S8 -> FJust (_, i)) = regprefix S128 b (codeByte 0x0f <> codeByte op <> reg8 x a) i-    -- TODO: xmm argument+  sseShift :: Word8 -> Word8 -> Word8 -> Operand RW S128 -> Operand r S8 -> CodeBuilder+  sseShift op x op' a@OpXMM b@(mkImmU 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)+  extension :: HasSize a => a -> Word8 -> CodeBuilder+  extension x p = codeByte $ p `shiftL` 1 .|. indicator (size x /= S8) -    extbits :: Operand r s -> Word8-    extbits = \case-        MemOp (Addr b _ i) -> maybe 0 indexReg b .|. case i of NoIndex -> 0; IndexReg _ x -> indexReg x `shiftL` 1-        RegOp r -> indexReg r-        _ -> 0-      where-        indexReg (NormalReg r) = r `shiftR` 3 .&. 1-        indexReg _ = 0+  extbits :: Operand r s -> Word8+  extbits = \case+    MemOp (Addr b _ i) -> maybe 0 indexReg b .|. case i of NoIndex -> 0; IndexReg _ x -> indexReg x `shiftL` 1+    RegOp r -> indexReg r+    _ -> 0+    where+      indexReg (NormalReg r) = r `shiftR` 3 .&. 1+      indexReg _ = 0 -    reg8 :: Word8 -> Operand r s -> CodeBuilder-    reg8 w x = codeByte $ operMode x `shiftL` 6 .|. w `shiftL` 3 .|. rc x-      where-        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 _                          = 0x3+  reg8 :: Word8 -> Operand r s -> CodeBuilder+  reg8 w x = codeByte $ operMode x `shiftL` 6 .|. w `shiftL` 3 .|. rc x+    where+      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 _              = 0x3 -        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+      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 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+  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 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+  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 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+  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 r s -> Operand r' t -> CodeBuilder-    op2g op dest src = regprefix2' dest src op $ reg2x8 src 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 -    reg2x8 :: (IsSize s, IsSize s') => Operand r s -> Operand r' s' -> CodeBuilder-    reg2x8 (RegOp r) x = reg8 (reg8_ r) x+  reg2x8 :: (IsSize s, IsSize s') => Operand r s -> Operand r' s' -> CodeBuilder+  reg2x8 (RegOp r) = reg8 (reg8_ r) -    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 r s -> CodeBuilder -> CodeBuilder+  op1_ r1 r2 dest = regprefix'' dest r1 (reg8 r2 dest) -    op1 :: IsSize s => Word8 -> Word8 -> Operand r s -> CodeBuilder-    op1 a b c = op1_ a b c mempty+  op1 :: IsSize s => Word8 -> Word8 -> Operand r s -> CodeBuilder+  op1 a b c = op1_ a b c mempty -    op1' :: Word8 -> Word8 -> Operand r S64 -> CodeBuilder-    op1' r1 r2 dest = regprefix S32 dest (codeByte r1 <> reg8 r2 dest) mempty+  op1' :: Word8 -> Word8 -> Operand r S64 -> CodeBuilder+  op1' r1 r2 dest = regprefix S32 dest (codeByte r1 <> reg8 r2 dest) mempty -    shiftOp :: IsSize s => Word8 -> Operand RW s -> Operand r S8 -> CodeBuilder-    shiftOp c dest (ImmOp (Immediate 1)) = op1 0x68 c dest-    shiftOp c dest (mkImmU S8 -> FJust (_, i)) = op1_ 0x60 c dest i-    shiftOp c dest RegCl = op1 0x69 c dest-    shiftOp _ _ _ = error "invalid shift operands"+  shiftOp :: IsSize s => Word8 -> Operand RW s -> Operand r S8 -> CodeBuilder+  shiftOp c dest (ImmOp (Immediate 1)) = op1 0x68 c dest+  shiftOp c dest (mkImmU S8 -> FJust (_, i)) = op1_ 0x60 c dest i+  shiftOp c dest RegCl = op1 0x69 c dest+  shiftOp _ _ _ = error "invalid shift operands" -    oneReg :: Word8 -> Reg t -> CodeBuilder-    oneReg x r = codeByte $ x `shiftL` 3 .|. reg8_ r+  oneReg :: Word8 -> Reg t -> CodeBuilder+  oneReg x r = codeByte $ x `shiftL` 3 .|. reg8_ r  pattern OpXMM <- RegOp XMM{}  -------------------------------------------------------------- asm codes  data LCode where-    Prebuilt    :: V.Vector Word8 -> LCode -> LCode-    EmptyCode   :: LCode-    AppendCode  :: CodeBuilder -> LCode -> LCode -> LCode-    CodeLine    :: CodeBuilder -> CodeLine -> LCode+  Prebuilt   :: V.Vector Word8 -> LCode -> LCode+  EmptyCode  :: LCode+  AppendCode :: CodeBuilder -> LCode -> LCode -> LCode+  CodeLine   :: CodeBuilder -> CodeLine -> LCode +#if MIN_VERSION_base(4,11,0)+instance Semigroup LCode where+  a <> b = AppendCode (mkCodeBuilder a <> mkCodeBuilder b) a b+#endif+ instance Monoid LCode where-    mempty  = EmptyCode-    mappend a b = AppendCode (mkCodeBuilder a <> mkCodeBuilder b) a b+  mempty  = EmptyCode -ret     = mkCodeLine Ret_-nop     = mkCodeLine Nop_-pushf   = mkCodeLine PushF_-popf    = mkCodeLine PopF_-cmc     = mkCodeLine Cmc_-clc     = mkCodeLine Clc_-stc     = mkCodeLine Stc_-cli     = mkCodeLine Cli_-sti     = mkCodeLine Sti_-cld     = mkCodeLine Cld_-std     = mkCodeLine Std_-inc a   = mkCodeLine (Inc_ a)-dec a   = mkCodeLine (Dec_ a)-not_ a  = mkCodeLine (Not_ a)-neg a   = mkCodeLine (Neg_ a)-bswap a = mkCodeLine (Bswap a)-bsf a b = mkCodeLine (Bsf a b)-bsr a b = mkCodeLine (Bsr a b)-bt a b  = mkCodeLine (Bt  a b)-add a b = mkCodeLine (Add_ a b)-or_  a b = mkCodeLine (Or_  a b)-adc a b = mkCodeLine (Adc_ a b)-sbb a b = mkCodeLine (Sbb_ a b)-and_ a b = mkCodeLine (And_ a b)-sub a b = mkCodeLine (Sub_ a b)-xor_ a b = mkCodeLine (Xor_ a b)-cmp a b = mkCodeLine (Cmp_ a b)-test a b = mkCodeLine (Test_ a b)-mov a b = mkCodeLine (Mov_ a b)+#if !MIN_VERSION_base(4,11,0)+  mappend a b = AppendCode (mkCodeBuilder a <> mkCodeBuilder b) a b+#endif++ret        = mkCodeLine Ret_+nop        = mkCodeLine Nop_+pushf      = mkCodeLine PushF_+popf       = mkCodeLine PopF_+cmc        = mkCodeLine Cmc_+clc        = mkCodeLine Clc_+stc        = mkCodeLine Stc_+cli        = mkCodeLine Cli_+sti        = mkCodeLine Sti_+cld        = mkCodeLine Cld_+std        = mkCodeLine Std_+inc a      = mkCodeLine (Inc_ a)+dec a      = mkCodeLine (Dec_ a)+not_ a     = mkCodeLine (Not_ a)+neg a      = mkCodeLine (Neg_ a)+bswap a    = mkCodeLine (Bswap a)+bsf a b    = mkCodeLine (Bsf a b)+bsr a b    = mkCodeLine (Bsr a b)+bt a b     = mkCodeLine (Bt  a b)+add a b    = mkCodeLine (Add_ a b)+or_  a b   = mkCodeLine (Or_  a b)+adc a b    = mkCodeLine (Adc_ a b)+sbb a b    = mkCodeLine (Sbb_ a b)+and_ a b   = mkCodeLine (And_ a b)+sub a b    = mkCodeLine (Sub_ a b)+xor_ a b   = mkCodeLine (Xor_ a b)+cmp a b    = mkCodeLine (Cmp_ a b)+test a b   = mkCodeLine (Test_ a b)+mov a b    = mkCodeLine (Mov_ a b) cmov c a b = mkCodeLine (Cmov_ c a b)-rol a b = mkCodeLine (Rol_ a b)-ror a b = mkCodeLine (Ror_ a b)-rcl a b = mkCodeLine (Rcl_ a b)-rcr a b = mkCodeLine (Rcr_ a b)-shl a b = mkCodeLine (Shl_ a b)-shr a b = mkCodeLine (Shr_ a b)-sar a b = mkCodeLine (Sar_ a b)-xchg a b = mkCodeLine (Xchg_ a b)+rol a b    = mkCodeLine (Rol_ a b)+ror a b    = mkCodeLine (Ror_ a b)+rcl a b    = mkCodeLine (Rcl_ a b)+rcr a b    = mkCodeLine (Rcr_ a b)+shl a b    = mkCodeLine (Shl_ a b)+shr a b    = mkCodeLine (Shr_ a b)+sar a b    = mkCodeLine (Sar_ a b)+xchg a b   = mkCodeLine (Xchg_ a b) movd   a b = mkCodeLine (Movd_   a b) movq   a b = mkCodeLine (Movq_   a b) movdqa a b = mkCodeLine (Movdqa_ a b)@@ -620,36 +634,33 @@ psrldq a b = mkCodeLine (Psrldq_ a b) psraw  a b = mkCodeLine (Psraw_  a b) psrad  a b = mkCodeLine (Psrad_  a b)-lea a b = mkCodeLine (Lea_ a b)-j a c   = mkCodeLine (J_ a Nothing c)-pop a   = mkCodeLine (Pop_ a)-push a  = mkCodeLine (Push_ a)-call a  = mkCodeLine (Call_ a)-jmpq a  = mkCodeLine (Jmpq_ a)-jmp b   = mkCodeLine (Jmp_ Nothing b)-db a    = mkCodeLine (Data_ a)-align a = mkCodeLine (Align_ a)+lea a b    = mkCodeLine (Lea_ a b)+j a c      = mkCodeLine (J_ a Nothing c)+pop a      = mkCodeLine (Pop_ a)+push a     = mkCodeLine (Push_ a)+call a     = mkCodeLine (Call_ a)+jmpq a     = mkCodeLine (Jmpq_ a)+jmp b      = mkCodeLine (Jmp_ Nothing b)+db a       = mkCodeLine (Data_ a)+align a    = mkCodeLine (Align_ a)  label :: CodeM Label label = do-    i <- CodeM get-    CodeM $ put $ i+1-    mkCodeLine Label_-    return $ Label i+  i <- CodeM get+  CodeM $ put $ i+1+  mkCodeLine Label_+  return $ Label i  mkCodeLine :: CodeLine -> Code mkCodeLine x = CodeM $ tell $ CodeLine (tellAddr <> mkCodeBuilder' x) x  tellAddr = CodeBuilder 0 0 $ do-    (c, _, _) <- lift getPast-    tell [Left c]----------------+  (c, _, _) <- lift getPast+  tell [Left c]  showCode = \case-    EmptyCode  -> return ()-    AppendCode _ a b -> showCode a >> showCode b-    Prebuilt _ c -> showCodeLine (Align_ 4) >> codeLine "{" >> showCode c >> codeLine "}"-    CodeLine _ x -> showCodeLine x+  EmptyCode  -> return ()+  AppendCode _ a b -> showCode a >> showCode b+  Prebuilt _ c -> showCodeLine (Align_ 4) >> codeLine "{" >> showCode c >> codeLine "}"+  CodeLine _ x -> showCodeLine x 
− CodeGen/X86/Examples.hs
@@ -1,102 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}
-module CodeGen.X86.Examples where
-
-import Foreign
-
-import CodeGen.X86
-
-foreign import ccall "dynamic" callWW :: FunPtr (Word64 -> Word64) -> Word64 -> Word64
-instance Callable (Word64 -> Word64) where dynCCall = callWW
-
-foreign import ccall "dynamic" callPW :: FunPtr (Ptr a -> Word64) -> Ptr a -> Word64
-instance Callable (Ptr a -> Word64) where dynCCall = callPW
-
-foreign import ccall "dynamic" callIO :: FunPtr (IO ()) -> IO ()
-instance Callable (IO ()) where dynCCall = callIO
-
-foreign import ccall "wrapper" createPtrWord64_Word64 :: (Word64 -> Word64) -> IO (FunPtr (Word64 -> Word64))
-instance CallableHs (Word64 -> Word64) where createHsPtr = createPtrWord64_Word64
-
------------------------------------------------------------------------------- 
--- * examples
-
--- | Example: identity function in Assembly (look at the source code)
---
--- Input: @rdi@ on Linux \/ System V, @rcx@ on Win64
---
--- Output: @rax@
-idCode = do
-    mov result arg1
-    ret
-
-idFun :: Word64 -> Word64
-idFun = compile idCode 
-
--- | Example: Fibonacci function in Assembly
-fibCode = saveNonVolatile $ do
-    mov rdi arg1
-    inc rdi
-    xor_ rdx rdx
-    mov rax 1
-    doWhile NZ $ do
-        mov rcx rax
-        mov rax rdx
-        add rdx rcx
-        dec rdi
-
-fibFun :: Word64 -> Word64
-fibFun = compile fibCode 
-
--- | Example: trace a register in Assembly
-tracedFibCode = saveNonVolatile $ do
-    mov rdi arg1
-    inc rdi
-    xor_ rdx rdx
-    mov rax 1
-    doWhile NZ $ do
-        mov rcx rax
-        mov rax rdx
-        add rdx rcx
-        dec rdi
-        traceReg "d" rax
-
-tracedFibFun :: Word64 -> Word64
-tracedFibFun = compile tracedFibCode 
-
--- | Example: call Haskell @fib@ function from Assembly
-callHsCode = do
-    callFun r11 (hsPtr fib)
-    ret
-
-fib :: Word64 -> Word64
-fib n = go n 0 1
-  where
-    go 0 a b = b `seq` a
-    go n a b = go (n-1) b (a+b)
-
-callHsFun :: Word64 -> Word64
-callHsFun = compile callHsCode 
-
--- | Example: call C @printf@ function from Assembly
---
-callCCode name = saveNonVolatile $ do
-    leaData arg1 $ CString "Hello %s!\n"
-    leaData arg2 $ CString name
-    xor_ rax rax                     -- zero XMM arguments ?????
-    callFun r11 printf
-
-callCFun :: String -> IO ()
-callCFun name = compile $ callCCode name
-
--------------------------------------------------------
-
-memTestFun :: Word64 -> IO Bool
-memTestFun v = do
-    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 $ do
-            mov rdi arg1
-            mov rax (addr rdi)
-    return $ compile code (r :: Ptr Word8) == v
-
-
CodeGen/X86/FFI.hs view
@@ -1,10 +1,8 @@-{-# language CPP #-}-{-# language ForeignFunctionInterface #-}-{-# language BangPatterns #-}-{-# language ViewPatterns #-} {-# language FlexibleInstances #-} {-# language FlexibleContexts #-}+{-# language ViewPatterns #-} {-# language TypeFamilies #-}+{-# language CPP #-} module CodeGen.X86.FFI where  -------------------------------------------------------
CodeGen/X86/Tests.hs view
@@ -1,418 +1,456 @@-{-# language LambdaCase #-}
-{-# language BangPatterns #-}
-{-# language ViewPatterns #-}
-{-# language PatternGuards #-}
-{-# language PatternSynonyms #-}
-{-# language NoMonomorphismRestriction #-}
-{-# language ScopedTypeVariables #-}
-{-# language RankNTypes #-}
-{-# language TypeFamilies #-}
-{-# language GADTs #-}
-{-# language DataKinds #-}
-{-# language KindSignatures #-}
-{-# language PolyKinds #-}
-{-# language FlexibleContexts #-}
-{-# language FlexibleInstances #-}
-{-# language GeneralizedNewtypeDeriving #-}
-{-# language RecursiveDo #-}
-{-# LANGUAGE TemplateHaskell #-}
-module CodeGen.X86.Tests (runTests) where
-
-import Data.Monoid
-import Data.Maybe
-import Data.List
-import Data.Bits
-import Data.Int
-import Data.Word
-
-import Test.QuickCheck hiding ((.&.), label)
-import Debug.Trace
-
-import CodeGen.X86.Asm
-import CodeGen.X86.CodeGen
-import CodeGen.X86.FFI
-import CodeGen.X86.Utils
-
-import Foreign
-
-foreign import ccall "dynamic" dcb :: FunPtr Bool -> Bool
-instance Callable Bool where dynCCall = dcb
-
-------------------------------------------------------------------------------
-
-class HasSigned a where
-    type Signed a
-    toSigned   :: a -> Signed a
-    fromSigned :: Signed a -> a
-    shiftMask  :: a
-
-instance HasSigned Word8  where
-    type Signed Word8  = Int8
-    toSigned   = fromIntegral
-    fromSigned = fromIntegral
-    shiftMask  = 0x1f
-
-instance HasSigned Word16 where
-    type Signed Word16 = Int16
-    toSigned   = fromIntegral
-    fromSigned = fromIntegral
-    shiftMask  = 0x1f
-
-instance HasSigned Word32 where
-    type Signed Word32 = Int32
-    toSigned   = fromIntegral
-    fromSigned = fromIntegral
-    shiftMask  = 0x1f
-
-instance HasSigned Word64 where
-    type Signed Word64 = Int64
-    toSigned   = fromIntegral
-    fromSigned = fromIntegral
-    shiftMask  = 0x3f
-
-------------------------------------------------------------------------------
-
-prop_integral x@(Integral y) = x == y
-
-------------------------------------------------------------------------------
-
-instance Arbitrary Size  where arbitrary = elements [S8, S16, S32, S64]
-
-instance Arbitrary Scale where arbitrary = elements [s1, s2, s4, s8]
-
-arbVal :: Size -> Gen Int64
-arbVal S8  = fromIntegral <$> (arbitrary :: Gen Int8)
-arbVal S16 = fromIntegral <$> (arbitrary :: Gen Int16)
-arbVal S32 = fromIntegral <$> (arbitrary :: Gen Int32)
-arbVal S64 = fromIntegral <$> (arbitrary :: Gen Int64)
-
-genReg8 :: Gen (Reg S8)
-genReg8 = elements ((NormalReg <$> [0..15]) ++ (HighReg <$> [0..3]))
-genReg16 :: Gen (Reg S16)
-genReg16 = NormalReg <$> elements [0..15]
-genReg32 :: Gen (Reg S32)
-genReg32 = NormalReg <$> elements [0..15]
-genReg64 :: Gen (Reg S64)
-genReg64 = NormalReg <$> elements [0..15]
-
-instance IsSize s => Arbitrary (Reg s) where
-    arbitrary = f (ssize :: SSize s) where
-        f :: SSize s -> Gen (Reg s)
-        f SSize8  = genReg8
-        f SSize16 = genReg16
-        f SSize32 = genReg32
-        f SSize64 = genReg64
-
-genRegs = RegOp <$> arbitrary
-
-genIPBase = pure $ ipRel $ Label 0
-
-instance Arbitrary (Addr S64) where
-    arbitrary = suchThat (Addr <$> base <*> disp <*> index) ok
-      where
-        ok (Addr Nothing _ NoIndex) = False
-        ok (Addr Nothing _ (IndexReg sc _)) = sc == s1
-        ok _ = True
-        base = oneof
-            [ return Nothing
-            , Just <$> arbitrary
-            ]
-        disp = oneof
-            [ return NoDisp
-            , Disp <$> arbitrary
-            ]
-        index = oneof
-            [ return NoIndex
-            , IndexReg <$> arbitrary <*> iregs
-            ]
-        iregs = NormalReg <$> elements ([0..15] \\ [4])      -- sp cannot be index
-
-genMems = MemOp <$> (arbitrary :: Gen (Addr S64))
-
-instance IsSize s => Arbitrary (Operand RW s) where
-    arbitrary = oneof
-        [ genRegs
-        , genMems
-        , genIPBase
-        ]
-
-instance IsSize s => Arbitrary (Operand R s) where
-    arbitrary = oneof
-        [ fromIntegral <$> oneof (arbVal <$> [S8, S16, S32, S64])
-        , genRegs
-        , genMems
-        , genIPBase
-        ]
-
-instance Arbitrary CodeLine where
-    arbitrary = oneof
-        [ op2 Add_
-        , op2 Or_
-        , op2 Adc_
-        , op2 Sbb_
-        , op2 And_
-        , op2 Sub_
-        , op2 Xor_
-        , op2 Cmp_
-        , op2 Test_
-        , op2' Rol_
-        , op2' Ror_
-        , op2' Rcl_
-        , op2' Rcr_
-        , op2' Shl_
-        , op2' Shr_
-        , op2' Sar_
-        , op2'' Mov_
-        ]
-      where
-        op2 :: (forall s . IsSize s => Operand RW s -> Operand R s -> CodeLine) -> Gen CodeLine
-        op2 op = oneof
-            [ 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 RW s -> Operand R s -> CodeLine) -> Gen (Operand RW s) -> Gen (Operand R s) -> Gen CodeLine
-            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 RW s -> Operand R s -> CodeLine) -> Gen CodeLine
-        op2'' op = oneof
-            [ 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 RW s -> Operand R s -> CodeLine) -> Gen (Operand RW s) -> Gen (Operand R s) -> Gen CodeLine
-            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 RW s -> Operand R S8 -> CodeLine) -> Gen CodeLine
-        op2' op = oneof
-            [ 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
-                [ fromIntegral <$> (arbitrary :: Gen Word8)
-                , return cl
-                ]
-
-            f :: forall s . IsSize s => (Operand RW s -> Operand R S8 -> CodeLine) -> Gen (Operand RW s) -> Gen (Operand R S8) -> Gen CodeLine
-            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
-
-        okk (size -> s) (ImmOp (Immediate i)) = isJust (integralToBytes True (no64 s) i)
-        okk _ _ = True
-
-        -- TODO: remove
-        ok' RegOp{} RegOp{} = True
-        ok' a b | isMemOp a && isMemOp b = False
-        ok' a b = noteqreg a b
-
-        oki x@RegOp{} (ImmOp (Immediate i)) = isJust (integralToBytes True (size x) i)
-        oki a b = okk a b
-
----------------------------------------------------
-
-evalOp :: forall a . (HasSigned a, Integral a, Integral (Signed a), FiniteBits (Signed a), Num a, FiniteBits a) => CodeLine -> Bool -> a -> a -> ((Bool, Bool), a)
-evalOp op c = case op of
-    Add_{}  -> mk (+)
-    Or_{}   -> mk (.|.)
-    Adc_{}  -> mk $ if c then \a b -> a + b + 1 else (+)
-    Sbb_{}  -> mk $ if c then \a b -> a - b - 1 else (-)
-    And_{}  -> mk (.&.)
-    Sub_{}  -> mk (-)
-    Xor_{}  -> mk xor
-    Cmp_{}  -> mk_ (-) (\a b -> a)
-    Test_{} -> mk_ (.&.) (\a b -> a)
-    Mov_{}  -> \a b -> ((c, False), b)
-    Shl_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else a `testBit` (finiteBitSize a - i), False), a `shiftL` i)
-    Shr_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else a `testBit` (i-1), False), a `shiftR` i)
-    Sar_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else toSigned a `testBit'` (i-1), False), fromSigned (toSigned a `shiftR` i))
-    Rol_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else a `testBit` ((finiteBitSize a - i) `mod` finiteBitSize a), False), a `roL` i)
-    Ror_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else a `testBit` ((i-1) `mod` finiteBitSize a), False), a `roR` i)
-    Rcl_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) `mod` (finiteBitSize a + 1) in ((if i == 0 then c else a `testBit` (finiteBitSize a - i), False), rcL c a i)
-    Rcr_{}  -> \a b -> let i = fromIntegral (b .&. shiftMask) `mod` (finiteBitSize a + 1) in ((if i == 0 then c else a `testBit` (i-1), False), rcR c a i)
-
-  where
-    mk :: (forall b . (Num b, Bits b, Integral b) => b -> b -> b) -> a -> a -> ((Bool, Bool), a)
-    mk f = mk_ f f
-
-    mk_ :: (forall b . (Num b, Bits b, Integral b) => b -> b -> b) -> (a -> a -> a) -> a -> a -> ((Bool, Bool), a)
-    mk_ f g a b = ((extend (f a b) /= f (extend a) (extend b), sextend (f a b) /= f (sextend a) (sextend b)), g a b)
-
-    extend :: a -> Integer
-    extend = fromIntegral
-    sextend :: a -> Integer
-    sextend = fromIntegral . toSigned
-
-    rcL c a 0 = a
-    rcL c a i = (if c then setBit else clearBit) (a `shiftL` i .|. a `shiftR` (finiteBitSize a - i + 1)) (i - 1)
-
-    rcR c a 0 = a
-    rcR c a i = (if c then setBit else clearBit) (a `shiftR` i .|. a `shiftL` (finiteBitSize a - i + 1)) (finiteBitSize a - i)
-
-    roL a i = a `shiftL` j .|. a `shiftR` (finiteBitSize a - j)
-      where
-        j = i `mod` finiteBitSize a
-
-    roR a i = a `shiftR` j .|. a `shiftL` (finiteBitSize a - j)
-      where
-        j = i `mod` finiteBitSize a
-
-    testBit' a i
-        | isSigned a && i >= finiteBitSize a = testBit a (finiteBitSize a - 1)
-        | otherwise = testBit a i
-
-
-data InstrTest = IT String Code
-
-instance Show InstrTest where show (IT s _) = s
-
-instance Arbitrary InstrTest where
-    arbitrary = do
-        i <- arbitrary
-        cF <- arbitrary
-        let   fff :: forall s s' r . (IsSize s, IsSize s') => CodeLine -> (Operand RW s -> Operand r s' -> CodeLine) -> 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 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)
-                    ff (MemOp (Addr (Just x) _ _)) (RegOp x') | phisicalReg (SReg x) == phisicalReg (SReg x') = error "TODO" {-do
-                        (av, inita) <- mkVal a
-                        return (av, av, inita) -}
-                    ff a_ b_ = do
-                        (av, inita) <- mkVal f2 a_
-                        (bv, initb) <- mkVal f2 b_
-                        return (av, bv, inita . initb)
-
-                (av, bv, initab) <- ff a b
-                let
-                    code = mdo
-                        mapM_ push sr
-                        mov f1 rsp
-                        pushf
-                        pop rax
-                        push rax
-                        popf
-                        initab (initcf >> cc >> mova)
-                        mkRes
-                        mov rsp f1 {- <> traceReg "X" rdx' -}
-                        mapM_ pop $ reverse sr
-                        ret
-
-                    sr = [rsi, rdi, rbx, rbp, r12, r13, r14, r15]
-
-                    cc = mkCodeLine i
-                    initcf = if cF then stc else clc
-                    mova = case a of
-                        RegOp (NormalReg 0x2) -> return ()
-                        _ -> mov rdx' a
-                    mkRes = otest i $ if_ (if cF' then C else NC) (xor_ rax rax) $ do
-                        xor_ rax rax
-                        mov rcx res
-                        cmp rcx' rdx'
-                        unless NZ $ inc rax
-                    isShift = \case
-                        Rol_{} -> True
-                        Ror_{} -> True
-                        Rcl_{} -> True
-                        Rcr_{} -> True
-                        Shl_{} -> True
-                        Shr_{} -> True
-                        Sar_{} -> True
-                        _ -> False
-                    otest i x | isShift i = x
-                    otest _ x = if_ (if oF' then O else NO) (xor_ rax rax) x
-
-                    rcx' = resizeOperand rcx :: Operand RW s
-                    rdx' = resizeOperand rdx :: Operand RW s
-                    sa = size a
-
-                    ((cF', oF'), res) = case sa of
-                        S8  -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word8)
-                        S16 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word16)
-                        S32 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word32)
-                        S64 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word64)
-
-                    msg = unlines [show cc, "input a: " ++ show av, "input b: " ++ show bv, "input flags: " ++ show cF, "output: " ++ show res, "output flags: " ++ show cF' ++ " " ++ show oF']
-
-                return $ traceShow cc $ IT msg code
-
-        case i of
-            Add_ a_ b_ -> fff i Add_ a_ b_
-            Or_  a_ b_ -> fff i Or_  a_ b_
-            Adc_ a_ b_ -> fff i Adc_ a_ b_
-            Sbb_ a_ b_ -> fff i Sbb_ a_ b_
-            And_ a_ b_ -> fff i And_ a_ b_
-            Sub_ a_ b_ -> fff i Sub_ a_ b_
-            Xor_ a_ b_ -> fff i Xor_ a_ b_
-            Cmp_ a_ b_ -> fff i Cmp_ a_ b_
-            Test_ a_ b_ -> fff i Test_ a_ b_
-            Rol_ a_ b_ -> fff i Rol_ a_ b_
-            Ror_ a_ b_ -> fff i Ror_ a_ b_
-            Rcl_ a_ b_ -> fff i Rcl_ a_ b_
-            Rcr_ a_ b_ -> fff i Rcr_ a_ b_
-            Shl_ a_ b_ -> fff i Shl_ a_ b_
-            Shr_ a_ b_ -> fff i Shr_ a_ b_
-            Sar_ a_ b_ -> fff i Sar_ a_ b_
-            Mov_ a_ b_ -> fff i Mov_ a_ b_
-
-      where
-        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) (fromIntegral v) >>))
-        mkVal helper x@(IPMemOp LabelRelValue{}) = do
-            v <- arbVal $ size x
-            return (v, \c -> mdo
-                        jmp l
-                        db $ toBytes v
-                        l <- label
-                        c)
-        mkVal helper o@(MemOp (Addr (Just x) d i)) = do
-            v <- arbVal $ size o
-            (vi, setvi) <- case i of
-                NoIndex -> return (0, return ())
-                IndexReg sc i -> do
-                    x <- arbVal $ size i
-                    return (scaleFactor sc * x, mov (RegOp i) (fromIntegral x))
-            let
-                d' = (vi :: Int64) + case d of
-                    NoDisp -> 0
-                    Disp v -> fromIntegral v
-                rx = resizeOperand $ RegOp x :: Operand RW S64
-            return (v, ((leaData rx v >> mov helper (fromIntegral d') >> sub rx helper >> setvi) >>))
-        mkVal helper o@(MemOp (Addr Nothing d (IndexReg sc x))) = do
-            v <- arbVal $ size o
-            let
-                d' = case d of
-                    NoDisp -> 0 :: Int64
-                    Disp v -> fromIntegral v
-                rx = resizeOperand $ RegOp x :: Operand RW S64
-            return (v, ((leaData rx v >> mov helper (fromIntegral d') >> sub rx helper) >>))
-
-
-propInstr (IT _ c) = compile c :: Bool
-
-tests num = quickCheckWith stdArgs { maxSuccess = num } propInstr
-
------------------------------------------
-
-return []
-
--- | Run all tests
-runTests = do
-    $quickCheckAll
-    tests 2000
-
+{-# language LambdaCase #-}+{-# language BangPatterns #-}+{-# language ViewPatterns #-}+{-# language PatternGuards #-}+{-# language PatternSynonyms #-}+{-# language NoMonomorphismRestriction #-}+{-# language ScopedTypeVariables #-}+{-# language RankNTypes #-}+{-# language TypeFamilies #-}+{-# language GADTs #-}+{-# language DataKinds #-}+{-# language PolyKinds #-}+{-# language FlexibleContexts #-}+{-# language FlexibleInstances #-}+{-# language GeneralizedNewtypeDeriving #-}+{-# language RecursiveDo #-}+{-# LANGUAGE TemplateHaskell #-}+module CodeGen.X86.Tests+  ( runTests+  )+where++import           Data.Monoid+import           Data.Maybe+import           Data.List+import           Data.Bits+import           Data.Int+import           Data.Word++import           Test.QuickCheck         hiding ( (.&.)+                                                , label+                                                )+import           Debug.Trace++import           CodeGen.X86.Asm+import           CodeGen.X86.CodeGen+import           CodeGen.X86.FFI+import           CodeGen.X86.Utils++import           Foreign++foreign import ccall "dynamic" dcb :: FunPtr Bool -> Bool+instance Callable Bool where+  dynCCall = dcb++------------------------------------------------------------------------------++class HasSigned a where+    type Signed a+    toSigned   :: a -> Signed a+    fromSigned :: Signed a -> a+    shiftMask  :: a++instance HasSigned Word8  where+  type Signed Word8 = Int8+  toSigned   = fromIntegral+  fromSigned = fromIntegral+  shiftMask  = 0x1f++instance HasSigned Word16 where+  type Signed Word16 = Int16+  toSigned   = fromIntegral+  fromSigned = fromIntegral+  shiftMask  = 0x1f++instance HasSigned Word32 where+  type Signed Word32 = Int32+  toSigned   = fromIntegral+  fromSigned = fromIntegral+  shiftMask  = 0x1f++instance HasSigned Word64 where+  type Signed Word64 = Int64+  toSigned   = fromIntegral+  fromSigned = fromIntegral+  shiftMask  = 0x3f++------------------------------------------------------------------------------++prop_integral x@(Integral y) = x == y++------------------------------------------------------------------------------++instance Arbitrary Size  where+  arbitrary = elements [S8, S16, S32, S64]++instance Arbitrary Scale where+  arbitrary = elements [s1, s2, s4, s8]++arbVal :: Size -> Gen Int64+arbVal S8  = fromIntegral <$> (arbitrary :: Gen Int8)+arbVal S16 = fromIntegral <$> (arbitrary :: Gen Int16)+arbVal S32 = fromIntegral <$> (arbitrary :: Gen Int32)+arbVal S64 = fromIntegral <$> (arbitrary :: Gen Int64)++genReg8 :: Gen (Reg S8)+genReg8 = elements ((NormalReg <$> [0 .. 15]) ++ (HighReg <$> [0 .. 3]))+genReg16 :: Gen (Reg S16)+genReg16 = NormalReg <$> elements [0 .. 15]+genReg32 :: Gen (Reg S32)+genReg32 = NormalReg <$> elements [0 .. 15]+genReg64 :: Gen (Reg S64)+genReg64 = NormalReg <$> elements [0 .. 15]++instance IsSize s => Arbitrary (Reg s) where+  arbitrary = f (ssize :: SSize s)   where+    f :: SSize s -> Gen (Reg s)+    f SSize8  = genReg8+    f SSize16 = genReg16+    f SSize32 = genReg32+    f SSize64 = genReg64++genRegs = RegOp <$> arbitrary++genIPBase = pure $ ipRel $ Label 0++instance Arbitrary (Addr S64) where+  arbitrary = suchThat (Addr <$> base <*> disp <*> index) ok+   where+    ok (Addr Nothing _ NoIndex) = False+    ok (Addr Nothing _ (IndexReg sc _)) = sc == s1+    ok _ = True+    base  = oneof [return Nothing, Just <$> arbitrary]+    disp  = oneof [return NoDisp, Disp <$> arbitrary]+    index = oneof [return NoIndex, IndexReg <$> arbitrary <*> iregs]+    iregs = NormalReg <$> elements ([0 .. 15] \\ [4])      -- sp cannot be index++genMems = MemOp <$> (arbitrary :: Gen (Addr S64))++instance IsSize s => Arbitrary (Operand RW s) where+  arbitrary = oneof [genRegs, genMems, genIPBase]++instance IsSize s => Arbitrary (Operand R s) where+  arbitrary = oneof [fromIntegral <$> oneof (arbVal <$> [S8, S16, S32, S64]), genRegs, genMems, genIPBase]++instance Arbitrary CodeLine where+  arbitrary = oneof+    [ op2 Add_+    , op2 Or_+    , op2 Adc_+    , op2 Sbb_+    , op2 And_+    , op2 Sub_+    , op2 Xor_+    , op2 Cmp_+    , op2 Test_+    , op2' Rol_+    , op2' Ror_+    , op2' Rcl_+    , op2' Rcr_+    , op2' Shl_+    , op2' Shr_+    , op2' Sar_+    , op2'' Mov_+    ]+   where+    op2 :: (forall s . IsSize s => Operand RW s -> Operand R s -> CodeLine) -> Gen CodeLine+    op2 op = oneof+      [ 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 RW s -> Operand R s -> CodeLine)+        -> Gen (Operand RW s)+        -> Gen (Operand R s)+        -> Gen CodeLine+      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 RW s -> Operand R s -> CodeLine) -> Gen CodeLine+    op2'' op = oneof+      [ 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 RW s -> Operand R s -> CodeLine)+        -> Gen (Operand RW s)+        -> Gen (Operand R s)+        -> Gen CodeLine+      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 RW s -> Operand R S8 -> CodeLine) -> Gen CodeLine+    op2' op = oneof+      [ 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 [fromIntegral <$> (arbitrary :: Gen Word8), return cl]++      f+        :: forall s+         . IsSize s+        => (Operand RW s -> Operand R S8 -> CodeLine)+        -> Gen (Operand RW s)+        -> Gen (Operand R S8)+        -> Gen CodeLine+      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++    okk (size -> s) (ImmOp (Immediate i)) = isJust (integralToBytes True (no64 s) i)+    okk _           _                     = True++    -- TODO: remove+    ok' RegOp{} RegOp{}              = True+    ok' a b | isMemOp a && isMemOp b = False+    ok' a b                          = noteqreg a b++    oki x@RegOp{} (ImmOp (Immediate i)) = isJust (integralToBytes True (size x) i)+    oki a         b                     = okk a b++---------------------------------------------------++evalOp+  :: forall a+   . (HasSigned a, Integral a, Integral (Signed a), FiniteBits (Signed a), Num a, FiniteBits a)+  => CodeLine+  -> Bool+  -> a+  -> a+  -> ((Bool, Bool), a)+evalOp op c = case op of+  Add_{}  -> mk (+)+  Or_{}   -> mk (.|.)+  Adc_{}  -> mk $ if c then \a b -> a + b + 1 else (+)+  Sbb_{}  -> mk $ if c then \a b -> a - b - 1 else (-)+  And_{}  -> mk (.&.)+  Sub_{}  -> mk (-)+  Xor_{}  -> mk xor+  Cmp_{}  -> mk_ (-) (const a)+  Test_{} -> mk_ (.&.) (const a)+  Mov_{}  -> \a b -> ((c, False), b)+  Shl_{}  -> \a b ->+    let i = fromIntegral (b .&. shiftMask)+    in  ((if i == 0 then c else a `testBit` (finiteBitSize a - i), False), a `shiftL` i)+  Shr_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask) in ((if i == 0 then c else a `testBit` (i - 1), False), a `shiftR` i)+  Sar_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask)+    in  ((if i == 0 then c else toSigned a `testBit'` (i - 1), False), fromSigned (toSigned a `shiftR` i))+  Rol_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask)+    in  ((if i == 0 then c else a `testBit` ((finiteBitSize a - i) `mod` finiteBitSize a), False), a `roL` i)+  Ror_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask)+    in  ((if i == 0 then c else a `testBit` ((i - 1) `mod` finiteBitSize a), False), a `roR` i)+  Rcl_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask) `mod` (finiteBitSize a + 1)+    in  ((if i == 0 then c else a `testBit` (finiteBitSize a - i), False), rcL c a i)+  Rcr_{} -> \a b ->+    let i = fromIntegral (b .&. shiftMask) `mod` (finiteBitSize a + 1)+    in  ((if i == 0 then c else a `testBit` (i - 1), False), rcR c a i)++ where+  mk :: (forall b . (Num b, Bits b, Integral b) => b -> b -> b) -> a -> a -> ((Bool, Bool), a)+  mk f = mk_ f f++  mk_ :: (forall b . (Num b, Bits b, Integral b) => b -> b -> b) -> (a -> a -> a) -> a -> a -> ((Bool, Bool), a)+  mk_ f g a b = ((extend (f a b) /= f (extend a) (extend b), sextend (f a b) /= f (sextend a) (sextend b)), g a b)++  extend :: a -> Integer+  extend = fromIntegral+  sextend :: a -> Integer+  sextend = fromIntegral . toSigned++  rcL c a 0 = a+  rcL c a i = (if c then setBit else clearBit) (a `shiftL` i .|. a `shiftR` (finiteBitSize a - i + 1)) (i - 1)++  rcR c a 0 = a+  rcR c a i =+    (if c then setBit else clearBit) (a `shiftR` i .|. a `shiftL` (finiteBitSize a - i + 1)) (finiteBitSize a - i)++  roL a i = a `shiftL` j .|. a `shiftR` (finiteBitSize a - j) where j = i `mod` finiteBitSize a++  roR a i = a `shiftR` j .|. a `shiftL` (finiteBitSize a - j) where j = i `mod` finiteBitSize a++  testBit' a i | isSigned a && i >= finiteBitSize a = testBit a (finiteBitSize a - 1)+               | otherwise                          = testBit a i+++data InstrTest = IT String Code++instance Show InstrTest where+  show (IT s _) = s++instance Arbitrary InstrTest where+  arbitrary = do+    i  <- arbitrary+    cF <- arbitrary+    let fff+          :: forall s s' r+           . (IsSize s, IsSize s')+          => CodeLine+          -> (Operand RW s -> Operand r s' -> CodeLine)+          -> 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 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)+              ff (MemOp (Addr (Just x) _ _)) (RegOp x') | phisicalReg (SReg x) == phisicalReg (SReg x') = error "TODO" {-do+                        (av, inita) <- mkVal a+                        return (av, av, inita) -}+              ff a_ b_ = do+                (av, inita) <- mkVal f2 a_+                (bv, initb) <- mkVal f2 b_+                return (av, bv, inita . initb)++          (av, bv, initab) <- ff a b+          let code = mdo+                mapM_ push sr+                mov f1 rsp+                pushf+                pop rax+                push rax+                popf+                initab (initcf >> cc >> mova)+                mkRes+                mov rsp f1 {- <> traceReg "X" rdx' -}+                mapM_ pop $ reverse sr+                ret++              sr     = [rsi, rdi, rbx, rbp, r12, r13, r14, r15]++              cc     = mkCodeLine i+              initcf = if cF then stc else clc+              mova   = case a of+                RegOp (NormalReg 0x2) -> return ()+                _                     -> mov rdx' a+              mkRes = otest i $ if_ (if cF' then C else NC) (xor_ rax rax) $ do+                xor_ rax rax+                mov rcx res+                cmp rcx' rdx'+                unless NZ $ inc rax+              isShift = \case+                Rol_{} -> True+                Ror_{} -> True+                Rcl_{} -> True+                Rcr_{} -> True+                Shl_{} -> True+                Shr_{} -> True+                Sar_{} -> True+                _      -> False+              otest i x | isShift i = x+              otest _ x             = if_ (if oF' then O else NO) (xor_ rax rax) x++              rcx'              = resizeOperand rcx :: Operand RW s+              rdx'              = resizeOperand rdx :: Operand RW s+              sa                = size a++              ((cF', oF'), res) = case sa of+                S8  -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word8)+                S16 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word16)+                S32 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word32)+                S64 -> fromIntegral <$> evalOp op cF (fromIntegral av) (fromIntegral bv :: Word64)++              msg = unlines+                [ show cc+                , "input a: " ++ show av+                , "input b: " ++ show bv+                , "input flags: " ++ show cF+                , "output: " ++ show res+                , "output flags: " ++ show cF' ++ " " ++ show oF'+                ]++          return $ traceShow cc $ IT msg code++    case i of+      Add_  a_ b_ -> fff i Add_ a_ b_+      Or_   a_ b_ -> fff i Or_ a_ b_+      Adc_  a_ b_ -> fff i Adc_ a_ b_+      Sbb_  a_ b_ -> fff i Sbb_ a_ b_+      And_  a_ b_ -> fff i And_ a_ b_+      Sub_  a_ b_ -> fff i Sub_ a_ b_+      Xor_  a_ b_ -> fff i Xor_ a_ b_+      Cmp_  a_ b_ -> fff i Cmp_ a_ b_+      Test_ a_ b_ -> fff i Test_ a_ b_+      Rol_  a_ b_ -> fff i Rol_ a_ b_+      Ror_  a_ b_ -> fff i Ror_ a_ b_+      Rcl_  a_ b_ -> fff i Rcl_ a_ b_+      Rcr_  a_ b_ -> fff i Rcr_ a_ b_+      Shl_  a_ b_ -> fff i Shl_ a_ b_+      Shr_  a_ b_ -> fff i Shr_ a_ b_+      Sar_  a_ b_ -> fff i Sar_ a_ b_+      Mov_  a_ b_ -> fff i Mov_ a_ b_++   where+    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) (fromIntegral v) >>))+    mkVal helper x@(IPMemOp LabelRelValue{}) = do+      v <- arbVal $ size x+      return+        ( v+        , \c -> mdo+          jmp l+          db $ toBytes v+          l <- label+          c+        )+    mkVal helper o@(MemOp (Addr (Just x) d i)) = do+      v           <- arbVal $ size o+      (vi, setvi) <- case i of+        NoIndex       -> return (0, return ())+        IndexReg sc i -> do+          x <- arbVal $ size i+          return (scaleFactor sc * x, mov (RegOp i) (fromIntegral x))+      let d' = (vi :: Int64) + case d of+            NoDisp -> 0+            Disp v -> fromIntegral v+          rx = resizeOperand $ RegOp x :: Operand RW S64+      return (v, ((leaData rx v >> mov helper (fromIntegral d') >> sub rx helper >> setvi) >>))+    mkVal helper o@(MemOp (Addr Nothing d (IndexReg sc x))) = do+      v <- arbVal $ size o+      let d' = case d of+            NoDisp -> 0 :: Int64+            Disp v -> fromIntegral v+          rx = resizeOperand $ RegOp x :: Operand RW S64+      return (v, ((leaData rx v >> mov helper (fromIntegral d') >> sub rx helper) >>))+++propInstr (IT _ c) = compile c :: Bool++tests num = quickCheckWith stdArgs { maxSuccess = num } propInstr++-----------------------------------------++return []++-- | Run all tests+runTests = do+  $quickCheckAll+  tests 2000+
CodeGen/X86/Utils.hs view
@@ -1,92 +1,111 @@-{-# language CPP #-}
-{-# language BangPatterns #-}
-{-# language NoMonomorphismRestriction #-}
-{-# language ScopedTypeVariables #-}
-{-# language DataKinds #-}
-{-# language ForeignFunctionInterface #-}
-{-# language RecursiveDo #-}
-module CodeGen.X86.Utils where
-
-import Data.Char
-import Data.Monoid
-import Control.Monad
-import Foreign
-import System.Environment
-import Debug.Trace
-
-import CodeGen.X86.Asm
-import CodeGen.X86.CodeGen
-import CodeGen.X86.CallConv
-
--------------------------------------------------------------- derived constructs
-
--- | execute code unless condition is true
-unless cc x = mdo
-    j cc l
-    x
-    l <- label
-    return ()
-
--- | do while loop construction
-doWhile cc x = do
-    l <- label
-    x
-    j cc l
-
--- | if-then-else
-if_ cc a b = mdo
-    j (N cc) l1
-    a
-    jmp l2
-    l1 <- label
-    b
-    l2 <- label
-    return ()
-
-leaData r d = mdo
-    lea r $ ipRel8 l1
-    jmp l2
-    l1 <- label
-    db $ toBytes d
-    l2 <- label
-    return ()
-
------------------------------------------------------------------------------- 
-
-foreign import ccall "static stdio.h &printf" printf :: FunPtr a
-
------------------------------------------------------------------------------- 
--- * utils
-
-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
-
-instance HasBytes CString where
-    toBytes (CString cs) = mconcat $ toBytes . (fromIntegral :: Int -> Word8) . fromEnum <$> (cs ++ "\0")
-
--- | we should implement PUSHA and POPA later
-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 = sequence_ [ push r | r <-         all_regs_except_rsp ]
-pop_all  = sequence_ [ pop  r | r <- reverse all_regs_except_rsp ]
-
-traceReg :: IsSize s => String -> Operand RW s -> Code
-traceReg d r = do
-    pushf
-    push_all
-    mov' arg2 r
-    leaData arg1 (CString $ show r ++ " = %" ++ s ++ d ++ "\n")
-    xor_ rax rax
-    callFun r11 printf
-    pop_all
-    popf
-  where
-    s = case size r of
-        S8  -> "hh"
-        S16 -> "h"
-        S32 -> ""
-        S64 -> "l"
-
+{-# language NoMonomorphismRestriction #-}+{-# language ScopedTypeVariables #-}+{-# language DataKinds #-}+{-# language ForeignFunctionInterface #-}+{-# language RecursiveDo #-}+module CodeGen.X86.Utils where++import           Data.Char+import           Data.Monoid+import           Control.Monad+import           Foreign+import           System.Environment+import           Debug.Trace++import           CodeGen.X86.Asm+import           CodeGen.X86.CodeGen+import           CodeGen.X86.CallConv++-------------------------------------------------------------- derived constructs++-- | execute code unless condition is true+unless cc x = mdo+  j cc l+  x+  l <- label+  return ()++-- | do while loop construction+doWhile cc x = do+  l <- label+  x+  j cc l++-- | if-then-else+if_ cc a b = mdo+  j (N cc) l1+  a+  jmp l2+  l1 <- label+  b+  l2 <- label+  return ()++leaData r d = mdo+  lea r $ ipRel8 l1+  jmp l2+  l1 <- label+  db $ toBytes d+  l2 <- label+  return ()++------------------------------------------------------------------------------ ++foreign import ccall "static stdio.h &printf" printf :: FunPtr a++------------------------------------------------------------------------------ +-- * utils++mov' :: forall s s' r . IsSize s' => Operand RW s -> Operand r s' -> Code+mov' a = mov (resizeOperand a :: Operand RW s')++newtype CString = CString String++instance HasBytes CString where+  toBytes (CString cs) = mconcat $ toBytes . (fromIntegral :: Int -> Word8) . fromEnum <$> (cs ++ "\0")++-- | we should implement PUSHA and POPA later+{- HLINT ignore all_regs_except_rsp -}+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+  ]++{- HLINT ignore push_all -}+push_all = sequence_ [ push r | r <- all_regs_except_rsp ]++{- HLINT ignore pop_all -}+pop_all = sequence_ [ pop r | r <- reverse all_regs_except_rsp ]++traceReg :: IsSize s => String -> Operand RW s -> Code+traceReg d r = do+  pushf+  push_all+  mov' arg2 r+  leaData arg1 (CString $ show r ++ " = %" ++ s ++ d ++ "\n")+  xor_ rax rax+  callFun r11 printf+  pop_all+  popf+ where+  s = case size r of+    S8  -> "hh"+    S16 -> "h"+    S32 -> ""+    S64 -> "l"+
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
Test.hs view
@@ -1,4 +1,4 @@-import CodeGen.X86
-
-main = runTests
-
+import CodeGen.X86.Tests++main = runTests+
x86-64bit.cabal view
@@ -1,87 +1,89 @@-name:                x86-64bit
-version:             0.4.5
-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.
-license:             BSD3
-license-file:        LICENSE
-author:              Péter Diviánszky
-maintainer:          divipp@gmail.com
-category:            Code Generation
-build-type:          Simple
-cabal-version:       >=1.10
-stability:           Experimental
-tested-with:         GHC == 8.0.1
-extra-source-files:  README.md
-                     CHANGELOG.md
-                     TODO.md
-
-source-repository head
-  type:     git
-  location: https://github.com/divipp/x86-64
-
-library
-  exposed-modules:
-    CodeGen.X86
-    CodeGen.X86.Examples
-  other-modules:
-    Control.DeeperSeq
-    CodeGen.X86.Asm
-    CodeGen.X86.CodeGen
-    CodeGen.X86.CallConv
-    CodeGen.X86.FFI
-    CodeGen.X86.Utils
-    CodeGen.X86.Tests
-
-  default-language:    Haskell2010
-  other-extensions:
-    NoMonomorphismRestriction
-    LambdaCase
-    PatternSynonyms
-    ViewPatterns
-    TypeSynonymInstances
-    FlexibleInstances
-    TypeFamilies
-    GADTs
-    RankNTypes
-    RecordWildCards
-    DeriveFunctor
-    DeriveFoldable
-    DeriveTraversable
-    DataKinds
-    GeneralizedNewtypeDeriving
-    OverloadedStrings
-    TupleSections
-    ExistentialQuantification
-    ScopedTypeVariables
-
-  build-depends:
-    base >=4.8 && <4.10,
-    monads-tf >=0.1 && <0.2,
-    tardis >= 0.4 && <0.5,
-    vector >=0.11 && <0.12,
-    QuickCheck >=2.8 && <2.10,
-    deepseq
-
-  if os(windows)
-    build-depends: Win32
-
-  default-language:    Haskell2010
-
-test-suite test-x86-64bit
-  type:       exitcode-stdio-1.0
-  main-is:    Test.hs
-
-  build-depends:
-    base >=4.8 && <4.10,
-    monads-tf >=0.1 && <0.2,
-    tardis >= 0.4 && <0.5,
-    vector >=0.11 && <0.12,
-    QuickCheck >=2.8 && <2.10,
-    deepseq
-
-  if os(windows)
-    build-depends: Win32
-
-  default-language:    Haskell2010
-
+name:                x86-64bit+version:             0.4.6+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.+license:             BSD3+license-file:        LICENSE+author:              Péter Diviánszky+maintainer:          divipp@gmail.com+category:            Code Generation+build-type:          Simple+cabal-version:       >=1.10+stability:           Experimental+tested-with:         GHC == 8.0.1+extra-source-files:  README.md+                     CHANGELOG.md+                     TODO.md++source-repository head+  type:     git+  location: https://github.com/divipp/x86-64++library+  exposed-modules: CodeGen.X86+  other-modules:+    Control.DeeperSeq+    CodeGen.X86.Asm+    CodeGen.X86.CodeGen+    CodeGen.X86.CallConv+    CodeGen.X86.FFI+    CodeGen.X86.Utils++  default-language:    Haskell2010+  other-extensions:+    NoMonomorphismRestriction+    LambdaCase+    PatternSynonyms+    ViewPatterns+    TypeSynonymInstances+    FlexibleInstances+    TypeFamilies+    GADTs+    RankNTypes+    RecordWildCards+    DeriveFunctor+    DeriveFoldable+    DeriveTraversable+    DataKinds+    GeneralizedNewtypeDeriving+    OverloadedStrings+    TupleSections+    ExistentialQuantification+    ScopedTypeVariables++  build-depends:+    base       >= 4.8  && <4.14,+    monads-tf  >= 0.1  && <0.2,+    tardis     >= 0.4  && <0.5,+    vector     >= 0.11 && <0.13,+    deepseq++  if os(windows)+    build-depends: Win32++test-suite test-x86-64bit+  type:       exitcode-stdio-1.0+  main-is:    Test.hs+  other-modules:+    Control.DeeperSeq+    CodeGen.X86.Asm+    CodeGen.X86.CodeGen+    CodeGen.X86.CallConv+    CodeGen.X86.FFI+    CodeGen.X86.Utils+    CodeGen.X86.Tests++  build-depends:+    base       >= 4.8  && <4.14,+    monads-tf  >= 0.1  && <0.2,+    tardis     >= 0.4  && <0.5,+    vector     >= 0.11 && <0.13,+    QuickCheck >= 2.8  && <2.14,+    deepseq++  if os(windows)+    build-depends: Win32++  default-language:    Haskell2010+