write-you-a-haskell/chapter27/dsl/Codegen.hs
Stephen Diehl 73b43dcf89 Squashed commit of the following:
commit 41ba8c36a90cc11723b14ce6c45599eabdcfaa53
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 21:02:57 2015 -0500

    type provenance

commit be5eda941bb4c44b4c4af0ddbbd793643938f4ff
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 20:13:06 2015 -0500

    provenance prototype

commit 7aa958b9c279e7571f7c4887f6aa19443e16f6fb
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 19:35:08 2015 -0500

    fix misc typos

commit 52d60b3b2630e50ef0cd6ea5f0fa1f308d92e26d
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 15:15:58 2015 -0500

    license badge

commit 7d34274afe6f05a0002c8f87e5077b6a130b42b4
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 15:07:28 2015 -0500

    fix resolution for llvm cfg graphs

commit 14d9bc836ecc64f8e9acc60bcbd2da02335255b9
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 13:12:39 2015 -0500

    added codegen dsl stub

commit 0f74cdd6f95d0a1fe1cafd73e45cb1407709efd8
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 13:01:14 2015 -0500

    llvm cfg graphs

commit a199d721503985954060e7670c1d2f5e1a65dd11
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 10:56:54 2015 -0500

    source code font

commit c7db0c5d67b73d8633f08be093971877e2d6ede0
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sun Jan 18 09:59:37 2015 -0500

    change phrasing around recursion

commit 6903700db482524233262e722df54b1066218250
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sat Jan 17 18:20:06 2015 -0500

    contributors.md

commit 14d90a3f2ebf7ddf1229c084fe4a1e9fa13f2e41
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sat Jan 17 17:35:41 2015 -0500

    added llvm logo

commit d270df6d94cbf1ef9eddfdd64af5aabc36ebca72
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sat Jan 17 15:50:28 2015 -0500

    initial llvm chapter

commit e71b189c057ea9e399e90e47d9d49bb4cf12cda8
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Sat Jan 17 12:21:00 2015 -0500

    system-f typing rules

commit 2a7d5c7f137cf352eeae64836df634c98118f594
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Thu Jan 15 15:21:14 2015 -0500

    flesh out system-f

commit 7b3b2f0a2aea5e1102abe093cf5e0559090720aa
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Jan 14 22:22:14 2015 -0500

    started on extended parser

commit cdeaf1a2658f15346fe1dc665ca09e954cce6c2e
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Jan 14 17:25:02 2015 -0500

    creative commons license

commit f09d210be253a05fc8ad0827cd72ffa32404e2ba
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Jan 14 16:54:10 2015 -0500

    higher res images

commit 8555eadfea8843f5683621e6652857e4259fa896
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Jan 14 14:48:44 2015 -0500

    cover page

commit e5e542e92610f4bb4c5ac726ffa86cd1e07753e3
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Tue Jan 13 17:31:01 2015 -0500

    initial happy/alex parser
2015-01-18 21:04:01 -05:00

282 lines
8.3 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Codegen where
import Data.Word
import Data.String
import Data.List
import Data.Function
import qualified Data.Map as Map
import Control.Monad.State
import Control.Applicative
import LLVM.General.AST
import LLVM.General.AST.Global
import qualified LLVM.General.AST as AST
import qualified LLVM.General.AST.Constant as C
import qualified LLVM.General.AST.Attribute as A
import qualified LLVM.General.AST.CallingConvention as CC
import qualified LLVM.General.AST.FloatingPointPredicate as FP
-------------------------------------------------------------------------------
-- Module Level
-------------------------------------------------------------------------------
newtype LLVM a = LLVM { unLLVM :: State AST.Module a }
deriving (Functor, Applicative, Monad, MonadState AST.Module )
runLLVM :: AST.Module -> LLVM a -> AST.Module
runLLVM = flip (execState . unLLVM)
emptyModule :: String -> AST.Module
emptyModule label = defaultModule { moduleName = label }
addDefn :: Definition -> LLVM ()
addDefn d = do
defs <- gets moduleDefinitions
modify $ \s -> s { moduleDefinitions = defs ++ [d] }
define :: Type -> String -> [(Type, Name)] -> Codegen a -> LLVM ()
define retty label argtys body = addDefn $
GlobalDefinition $ functionDefaults {
name = Name label
, parameters = ([Parameter ty nm [] | (ty, nm) <- argtys], False)
, returnType = retty
, basicBlocks = bls
}
where
bls = createBlocks $ execCodegen $ do
enter <- addBlock entryBlockName
void $ setBlock enter
body
external :: Type -> String -> [(Type, Name)] -> LLVM ()
external retty label argtys = addDefn $
GlobalDefinition $ functionDefaults {
name = Name label
, parameters = ([Parameter ty nm [] | (ty, nm) <- argtys], False)
, returnType = retty
, basicBlocks = []
}
---------------------------------------------------------------------------------
-- Types
-------------------------------------------------------------------------------
-- IEEE 754 double
double :: Type
double = FloatingPointType 64 IEEE
-------------------------------------------------------------------------------
-- Names
-------------------------------------------------------------------------------
type Names = Map.Map String Int
uniqueName :: String -> Names -> (String, Names)
uniqueName nm ns =
case Map.lookup nm ns of
Nothing -> (nm, Map.insert nm 1 ns)
Just ix -> (nm ++ show ix, Map.insert nm (ix+1) ns)
instance IsString Name where
fromString = Name . fromString
-------------------------------------------------------------------------------
-- Codegen State
-------------------------------------------------------------------------------
type SymbolTable = [(String, Operand)]
data CodegenState
= CodegenState {
currentBlock :: Name -- Name of the active block to append to
, blocks :: Map.Map Name BlockState -- Blocks for function
, symtab :: SymbolTable -- Function scope symbol table
, blockCount :: Int -- Count of basic blocks
, count :: Word -- Count of unnamed instructions
, names :: Names -- Name Supply
} deriving Show
data BlockState
= BlockState {
idx :: Int -- Block index
, stack :: [Named Instruction] -- Stack of instructions
, term :: Maybe (Named Terminator) -- Block terminator
} deriving Show
-------------------------------------------------------------------------------
-- Codegen Operations
-------------------------------------------------------------------------------
newtype Codegen a = Codegen { runCodegen :: State CodegenState a }
deriving (Functor, Applicative, Monad, MonadState CodegenState )
sortBlocks :: [(Name, BlockState)] -> [(Name, BlockState)]
sortBlocks = sortBy (compare `on` (idx . snd))
createBlocks :: CodegenState -> [BasicBlock]
createBlocks m = map makeBlock $ sortBlocks $ Map.toList (blocks m)
makeBlock :: (Name, BlockState) -> BasicBlock
makeBlock (l, (BlockState _ s t)) = BasicBlock l s (maketerm t)
where
maketerm (Just x) = x
maketerm Nothing = error $ "Block has no terminator: " ++ (show l)
entryBlockName :: String
entryBlockName = "entry"
emptyBlock :: Int -> BlockState
emptyBlock i = BlockState i [] Nothing
emptyCodegen :: CodegenState
emptyCodegen = CodegenState (Name entryBlockName) Map.empty [] 1 0 Map.empty
execCodegen :: Codegen a -> CodegenState
execCodegen m = execState (runCodegen m) emptyCodegen
fresh :: Codegen Word
fresh = do
i <- gets count
modify $ \s -> s { count = 1 + i }
return $ i + 1
instr :: Instruction -> Codegen (Operand)
instr ins = do
n <- fresh
let ref = (UnName n)
blk <- current
let i = stack blk
modifyBlock (blk { stack = i ++ [ref := ins] } )
return $ local ref
terminator :: Named Terminator -> Codegen (Named Terminator)
terminator trm = do
blk <- current
modifyBlock (blk { term = Just trm })
return trm
-------------------------------------------------------------------------------
-- Block Stack
-------------------------------------------------------------------------------
entry :: Codegen Name
entry = gets currentBlock
addBlock :: String -> Codegen Name
addBlock bname = do
bls <- gets blocks
ix <- gets blockCount
nms <- gets names
let new = emptyBlock ix
(qname, supply) = uniqueName bname nms
modify $ \s -> s { blocks = Map.insert (Name qname) new bls
, blockCount = ix + 1
, names = supply
}
return (Name qname)
setBlock :: Name -> Codegen Name
setBlock bname = do
modify $ \s -> s { currentBlock = bname }
return bname
getBlock :: Codegen Name
getBlock = gets currentBlock
modifyBlock :: BlockState -> Codegen ()
modifyBlock new = do
active <- gets currentBlock
modify $ \s -> s { blocks = Map.insert active new (blocks s) }
current :: Codegen BlockState
current = do
c <- gets currentBlock
blks <- gets blocks
case Map.lookup c blks of
Just x -> return x
Nothing -> error $ "No such block: " ++ show c
-------------------------------------------------------------------------------
-- Symbol Table
-------------------------------------------------------------------------------
assign :: String -> Operand -> Codegen ()
assign var x = do
lcls <- gets symtab
modify $ \s -> s { symtab = [(var, x)] ++ lcls }
getvar :: String -> Codegen Operand
getvar var = do
syms <- gets symtab
case lookup var syms of
Just x -> return x
Nothing -> error $ "Local variable not in scope: " ++ show var
-------------------------------------------------------------------------------
-- References
local :: Name -> Operand
local = LocalReference
global :: Name -> C.Constant
global = C.GlobalReference
externf :: Name -> Operand
externf = ConstantOperand . C.GlobalReference
-- Arithmetic and Constants
fadd :: Operand -> Operand -> Codegen Operand
fadd a b = instr $ FAdd a b []
fsub :: Operand -> Operand -> Codegen Operand
fsub a b = instr $ FSub a b []
fmul :: Operand -> Operand -> Codegen Operand
fmul a b = instr $ FMul a b []
fdiv :: Operand -> Operand -> Codegen Operand
fdiv a b = instr $ FDiv a b []
fcmp :: FP.FloatingPointPredicate -> Operand -> Operand -> Codegen Operand
fcmp cond a b = instr $ FCmp cond a b []
cons :: C.Constant -> Operand
cons = ConstantOperand
uitofp :: Type -> Operand -> Codegen Operand
uitofp ty a = instr $ UIToFP a ty []
toArgs :: [Operand] -> [(Operand, [A.ParameterAttribute])]
toArgs = map (\x -> (x, []))
-- Effects
call :: Operand -> [Operand] -> Codegen Operand
call fn args = instr $ Call False CC.C [] (Right fn) (toArgs args) [] []
alloca :: Type -> Codegen Operand
alloca ty = instr $ Alloca ty Nothing 0 []
store :: Operand -> Operand -> Codegen Operand
store ptr val = instr $ Store False ptr val Nothing 0 []
load :: Operand -> Codegen Operand
load ptr = instr $ Load False ptr Nothing 0 []
-- Control Flow
br :: Name -> Codegen (Named Terminator)
br val = terminator $ Do $ Br val []
cbr :: Operand -> Name -> Name -> Codegen (Named Terminator)
cbr cond tr fl = terminator $ Do $ CondBr cond tr fl []
phi :: Type -> [(Operand, Name)] -> Codegen Operand
phi ty incoming = instr $ Phi ty incoming []
ret :: Operand -> Codegen (Named Terminator)
ret val = terminator $ Do $ Ret (Just val) []