/
Codegen.hs
144 lines (119 loc) · 4.72 KB
/
Codegen.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{-# LANGUAGE OverloadedStrings #-}
-- | Generates LLVM ASTs.
module Codegen
( genLLVM
) where
import Data.String
import qualified Control.Monad
import Control.Monad.State
import LLVM.AST.AddrSpace
import LLVM.AST hiding (function)
import LLVM.AST.Float
import qualified LLVM.AST.IntegerPredicate as C
import LLVM.AST.Type as AST
import LLVM.AST.Typed
import qualified LLVM.AST.Float as F
import qualified LLVM.AST.Constant as C
import LLVM.IRBuilder.Constant
import LLVM.IRBuilder.Instruction hiding (sdiv)
import LLVM.IRBuilder.Module
import LLVM.IRBuilder.Monad
import Lang
type SymbolTable = [(String, Operand)]
data CodegenState = CodegenState { symtab :: SymbolTable, locals :: SymbolTable }
emptyCodegen :: CodegenState
emptyCodegen = CodegenState [] []
-- | Generates an LLVM module for the given compilation unit.
genLLVM :: CompilationUnit -> Module
genLLVM (CompilationUnit functions) = evalState (buildModuleT "program" $ mapM_ genFunction functions) emptyCodegen
genFunction :: Lang.Function -> ModuleBuilderT (State CodegenState) ()
genFunction (Lang.Function name parameters returnType (Block definition)) = do
modify $ \ s -> s { locals = map (\ (ParameterDeclaration name langType) -> (name, LocalReference (llvmType langType) (fromString name))) parameters }
let retty = llvmReturnType returnType
let argTypes = map (\ (ParameterDeclaration _ langType) -> llvmType langType) parameters
let fn = FunctionType {resultType = retty, argumentTypes = argTypes, isVarArg = False}
let op = ConstantOperand $ C.GlobalReference (PointerType fn (AddrSpace 0)) (Name $ fromString name)
symbols <- gets symtab
modify $ \ s -> s { symtab = (name, op) : symbols }
function (fromString name) (map parameter parameters) (llvmReturnType returnType) $ \ _ ->
block `named` "entry" >> mapM_ genStatement definition
return ()
parameter :: ParameterDeclaration -> (AST.Type, ParameterName)
parameter (ParameterDeclaration identifier langType) = (llvmType langType, fromString identifier)
genStatement :: Lang.Statement -> IRBuilderT (ModuleBuilderT (State CodegenState)) ()
genStatement (Return expr) = ret =<< genExpression expr
genStatement (Declaration name langType Nothing) = return ()
genStatement (Declaration name langType (Just definition)) = do
op <- genExpression definition
lcls <- gets locals
modify $ \ s -> s { locals = (name, op) : lcls }
genStatement (Assignment name expr) = do
op <- genExpression expr
lcls <- gets locals
modify $ \ s -> s { locals = (name, op) : lcls }
genStatement (Unary op (Variable x)) = do
let one = ConstantOperand (C.Int 64 1)
let ins = case op of
Increment -> add one
Decrement -> flip sub one
var <- genExpression (Variable x)
var' <- ins var
lcls <- gets locals
modify $ \ s -> s { locals = (x, var') : lcls }
genStatement (If cond (Block thenBlock) elseBlock) = do
result <- genComparison cond
condBr result (Name "then") (Name "else")
block `named` "then"
mapM_ genStatement thenBlock
block `named` "else"
case elseBlock of
Nothing -> return ()
Just (Block elseBlock) -> mapM_ genStatement elseBlock
genExpression :: Lang.Expression -> IRBuilderT (ModuleBuilderT (State CodegenState)) Operand
genExpression (Atomic a) = return $ genAtomic a
genExpression (Variable name) = do
lcls <- gets locals
case lookup name lcls of
Nothing -> fail $ "Variable " ++ name ++ " not declared."
Just op -> return op
genExpression (Invocation name parameters) = do
symbols <- gets symtab
case lookup name symbols of
Nothing -> fail $ "Function " ++ name ++ " not declared."
Just callee -> do
parameters <- mapM genExpression parameters
call callee (map (\ p -> (p, [])) parameters)
genExpression (Math op a b) =
let ins = case op of
Addition -> add
Subtraction -> sub
Division -> sdiv
Multiplication -> mul
Modulo -> urem
in
genExpression a >>= \opa -> genExpression b >>= \opb -> ins opa opb
genComparison :: Lang.Expression -> IRBuilderT (ModuleBuilderT (State CodegenState)) Operand
genComparison (Comparison op a b) = do
let ty = case op of
Eq -> C.EQ
Ne -> C.NE
Lt -> C.SLT
Gt -> C.SGT
Le -> C.SLE
Ge -> C.SGE
opa <- genExpression a
opb <- genExpression b
icmp ty opa opb
genAtomic :: Atomic -> Operand
genAtomic (Integer i) = ConstantOperand (C.Int 64 i)
genAtomic (Float f) = ConstantOperand (C.Float $ Double f)
llvmReturnType :: ReturnType -> AST.Type
llvmReturnType (Just t) = llvmType t
llvmReturnType Nothing = VoidType
llvmType :: Lang.Type -> AST.Type
llvmType t =
case t of
I64 -> i64
F64 -> AST.double
sdiv :: MonadIRBuilder m => Operand -> Operand -> m Operand
sdiv a b = emitInstr (typeOf a) $ SDiv False a b []