mirror of
https://github.com/sdiehl/write-you-a-haskell.git
synced 2024-09-17 14:37:16 +03:00
73b43dcf89
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
282 lines
8.3 KiB
Haskell
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) []
|