packages feed

x86-64bit-0.1: examples/Main.hs

{-# 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 #-}

import Data.Char
import Data.Monoid
import qualified Data.ByteString.Lazy as BS
import Control.Monad
import Foreign
import System.Environment
import Debug.Trace

import CodeGen.X86
import CodeGen.X86.Tests

------------------------------------------------------------------------------ utils

-- helper to call a function
callFun :: Operand S64 RW -> FunPtr a -> Code
callFun r p = Mov r (imm $ fromIntegral $ ptrToIntPtr $ castFunPtrToPtr p) <> Call r

foreign import ccall "static stdio.h &printf" printf :: FunPtr a

mov' :: forall s s' r . IsSize s' => Operand s RW -> Operand s' r -> Code
mov' a b = Mov (resizeOperand a :: Operand s' RW) b

newtype CString = CString String

instance HasBytes CString where
    toBytes (CString cs) = mconcat $ toBytes . (fromIntegral :: Int -> Word8) . fromEnum <$> (cs ++ "\0")

traceReg :: IsSize s => String -> Operand s RW -> Code
traceReg d r = 
       Push rsi <> Push rdi <> Push rax <> Push rcx <> Push rdx
    <> mov' rsi r <> leaData rdi (CString $ show r ++ " = %" ++ s ++ d ++ "\n") <> callFun rax printf
    <> Pop rdx <> Pop rcx <> Pop rax <> Pop rdi <> Pop rsi
  where
    s = case size r of
        S8  -> "hh"
        S16 -> "h"
        S32 -> ""
        S64 -> "l"

pattern Show :: (Show a, Read a) => a -> String
pattern Show x <- (maybeRead -> Just x)
  where Show x =  show x

maybeRead x = case reads x of
    ((y, cs): _) | all isSpace cs -> Just y
    _ -> Nothing

------------------------------------------------------------------------------ examples

main = do
    args <- getArgs
    case args of

        ["id", Show n] -> do
            print idCode
            print $ (compile idCode :: Word64 -> Word64) n

        ["fib", Show n] -> do
            print fibCode
            print $ (compile fibCode :: Word64 -> Word64) n

        ["fib", "traced", Show n] -> do
            print tracedFibCode
            print $ (compile tracedFibCode :: Word64 -> Word64) n

        -- for time comparison
        ["hsfib", Show n] -> print $ fib n

        ["callhs", Show n] -> do
            print callHsCode
            print $ (compile $ callHsCode :: Word64 -> Word64) n

        ["callc", name] -> do
            print $ callCCode name
            compile $ callCCode name

        ["memtest", Show v] -> do
            r <- memalign 8 8
            pokeByteOff r 0 (v :: Word64)
            print $ compile (Mov rax (MemOp $ base rdi) <> Ret) r == v

        ["tests"] -> do
            tests
            runTests
            return ()

        ["fib", "writebytes"]
            -> BS.writeFile "fib.bytes" $ BS.pack $ getBytes $ codeBytes fibCode

        _ -> putStrLn "wrong command line arguments"

idCode
    =  Mov rax rdi
    <> Ret

fibCode
    =  Inc rdi
    <> Xor rdx rdx
    <> Mov rax (imm 1)
    <> (Mov rcx rax <> Mov rax rdx <> Add rdx rcx <> Dec rdi) `j_back` NZ
    <> Ret

tracedFibCode
    =  Inc rdi
    <> Xor rdx rdx
    <> Mov rax (imm 1)
    <> (Mov rcx rax <> Mov rax rdx <> Add rdx rcx <> traceReg "d" rax <> Dec rdi) `j_back` NZ
    <> Ret

callHsCode
    =  callFun rdx (hsPtr fib)
    <> Ret

callCCode name
    =  leaData rdi (CString "Hello %s!\n")
    <> leaData rsi (CString name)
    <> callFun rdx printf
    <> Ret

fib :: Word64 -> Word64
fib n = go n 0 1
  where
    go 0 !a !b = a
    go n a b = go (n-1) b (a+b)