Types for data types are now created.
This commit is contained in:
parent
272fbe3504
commit
262543931c
3 changed files with 94 additions and 60 deletions
138
src/Compiler.hs
138
src/Compiler.hs
|
|
@ -3,26 +3,28 @@
|
||||||
|
|
||||||
module Compiler (compile) where
|
module Compiler (compile) where
|
||||||
|
|
||||||
import Auxiliary (snoc)
|
import Auxiliary (snoc)
|
||||||
import Control.Monad.State (StateT, execStateT, gets, modify)
|
import Control.Monad.State (StateT, execStateT, gets, modify)
|
||||||
import Data.Map (Map)
|
import Data.List.Extra (trim)
|
||||||
import qualified Data.Map as Map
|
import Data.Map (Map)
|
||||||
import Data.Tuple.Extra (dupe, first, second)
|
import qualified Data.Map as Map
|
||||||
import qualified Grammar.Abs as GA
|
import Data.Tuple.Extra (dupe, first, second)
|
||||||
import Grammar.ErrM (Err)
|
import qualified Grammar.Abs as GA
|
||||||
import LlvmIr (CallingConvention (..), LLVMComp (..),
|
import Grammar.ErrM (Err)
|
||||||
LLVMIr (..), LLVMType (..),
|
import LlvmIr (CallingConvention (..), LLVMComp (..),
|
||||||
LLVMValue (..), Visibility (..),
|
LLVMIr (..), LLVMType (..),
|
||||||
llvmIrToString)
|
LLVMValue (..), Visibility (..),
|
||||||
import TypeChecker (partitionType)
|
llvmIrToString)
|
||||||
import TypeCheckerIr (Bind (..), Case (..), Exp (..), Id,
|
import System.Process.Extra (readCreateProcess, shell)
|
||||||
Ident (..), Program (..),
|
import TypeChecker (partitionType)
|
||||||
Type (TFun, TInt))
|
import TypeCheckerIr (Bind (..), Case (..), Exp (..), Id,
|
||||||
|
Ident (..), Program (..), Type (..))
|
||||||
|
|
||||||
-- | The record used as the code generator state
|
-- | The record used as the code generator state
|
||||||
data CodeGenerator = CodeGenerator
|
data CodeGenerator = CodeGenerator
|
||||||
{ instructions :: [LLVMIr]
|
{ instructions :: [LLVMIr]
|
||||||
, functions :: Map Id FunctionInfo
|
, functions :: Map Id FunctionInfo
|
||||||
|
, constructors :: Map Id FunctionInfo
|
||||||
, variableCount :: Integer
|
, variableCount :: Integer
|
||||||
, labelCount :: Integer
|
, labelCount :: Integer
|
||||||
}
|
}
|
||||||
|
|
@ -34,6 +36,7 @@ data FunctionInfo = FunctionInfo
|
||||||
{ numArgs :: Int
|
{ numArgs :: Int
|
||||||
, arguments :: [Id]
|
, arguments :: [Id]
|
||||||
}
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
-- | Adds a instruction to the CodeGenerator state
|
-- | Adds a instruction to the CodeGenerator state
|
||||||
emit :: LLVMIr -> CompilerState ()
|
emit :: LLVMIr -> CompilerState ()
|
||||||
|
|
@ -60,51 +63,62 @@ getNewLabel = do
|
||||||
-- | Produces a map of functions infos from a list of binds,
|
-- | Produces a map of functions infos from a list of binds,
|
||||||
-- which contains useful data for code generation.
|
-- which contains useful data for code generation.
|
||||||
getFunctions :: [Bind] -> Map Id FunctionInfo
|
getFunctions :: [Bind] -> Map Id FunctionInfo
|
||||||
getFunctions bs = Map.fromList $ map go bs
|
getFunctions bs = Map.fromList $ go bs
|
||||||
where
|
where
|
||||||
go (Bind id args _) =
|
go [] = []
|
||||||
|
go (Bind id args _ : xs) =
|
||||||
(id, FunctionInfo { numArgs=length args, arguments=args })
|
(id, FunctionInfo { numArgs=length args, arguments=args })
|
||||||
|
: go xs
|
||||||
|
go (DataStructure n cons : xs) = do
|
||||||
|
map (\(id, xs) -> ((id, TPol n), FunctionInfo {
|
||||||
|
numArgs=length xs, arguments=createArgs xs
|
||||||
|
})) cons
|
||||||
|
<> go xs
|
||||||
|
|
||||||
|
createArgs :: [Type] -> [Id]
|
||||||
|
createArgs xs = fst $ foldl (\(acc, l) t -> (acc ++ [(Ident ("arg_" <> show l) , t)],l+1)) ([], 0) xs
|
||||||
|
|
||||||
|
-- | Produces a map of functions infos from a list of binds,
|
||||||
|
-- which contains useful data for code generation.
|
||||||
|
getConstructors :: [Bind] -> Map Id FunctionInfo
|
||||||
|
getConstructors bs = Map.fromList $ go bs
|
||||||
|
where
|
||||||
|
go [] = []
|
||||||
|
go (DataStructure n cons : xs) = do
|
||||||
|
map (\(id, xs) -> ((id, TPol n), FunctionInfo {
|
||||||
|
numArgs=length xs, arguments=createArgs xs
|
||||||
|
})) cons
|
||||||
|
<> go xs
|
||||||
|
go (_: xs) = go xs
|
||||||
|
|
||||||
initCodeGenerator :: [Bind] -> CodeGenerator
|
initCodeGenerator :: [Bind] -> CodeGenerator
|
||||||
initCodeGenerator scs = CodeGenerator { instructions = defaultStart
|
initCodeGenerator scs = CodeGenerator { instructions = defaultStart
|
||||||
, functions = getFunctions scs
|
, functions = getFunctions scs
|
||||||
|
, constructors = getConstructors scs
|
||||||
, variableCount = 0
|
, variableCount = 0
|
||||||
, labelCount = 0
|
, labelCount = 0
|
||||||
}
|
}
|
||||||
{-
|
|
||||||
run :: Err String -> IO ()
|
run :: Err String -> IO ()
|
||||||
run s = do
|
run s = do
|
||||||
let s' = case s of
|
let s' = case s of
|
||||||
Right s -> s
|
Right s -> s
|
||||||
Left _ -> error "yo"
|
Left _ -> error "yo"
|
||||||
writeFile "llvm.ll" s'
|
writeFile "output/llvm.ll" s'
|
||||||
putStrLn . trim =<< readCreateProcess (shell "lli") s'
|
putStrLn . trim =<< readCreateProcess (shell "lli") s'
|
||||||
|
|
||||||
test :: Integer -> Program
|
test :: Integer -> Program
|
||||||
test v = Program [
|
test v = Program [
|
||||||
Bind (Ident "fibonacci", TInt) [(Ident "x", TInt)] (
|
DataStructure (Ident "Craig") [
|
||||||
ECase TInt (EId ("x", TInt)) [
|
(Ident "Bob", [TInt]),
|
||||||
(TInt,Case (CInt 0) (EInt 0)),
|
(Ident "Alice", [TInt, TInt])
|
||||||
Case (CInt 1) (EInt 1),
|
],
|
||||||
Case CatchAll (EAdd TInt
|
Bind (Ident "fibonacci", TInt) [(Ident "x", TInt)] (EId ("x",TInt)),
|
||||||
(EApp TInt (EId (Ident "fibonacci", TInt)) (
|
|
||||||
EAdd TInt (EId (Ident "x", TInt))
|
|
||||||
(EInt (fromIntegral ((maxBound :: Int) * 2)))
|
|
||||||
))
|
|
||||||
(EApp TInt (EId (Ident "fibonacci", TInt)) (
|
|
||||||
EAdd TInt (EId (Ident "x", TInt))
|
|
||||||
(EInt (fromIntegral ((maxBound :: Int) * 2 + 1)))
|
|
||||||
))
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Bind (Ident "main", TInt) [] (
|
Bind (Ident "main", TInt) [] (
|
||||||
EApp TInt (EId (Ident "fibonacci", TInt)) (EInt v) -- (EInt 92)
|
EApp TInt (EId (Ident "fibonacci", TInt)) (EInt v) -- (EInt 92)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
-}
|
|
||||||
{- | Compiles an AST and produces a LLVM Ir string.
|
{- | Compiles an AST and produces a LLVM Ir string.
|
||||||
An easy way to actually "compile" this output is to
|
An easy way to actually "compile" this output is to
|
||||||
Simply pipe it to LLI
|
Simply pipe it to LLI
|
||||||
|
|
@ -115,8 +129,14 @@ compile (Program scs) = do
|
||||||
llvmIrToString . instructions <$> execStateT (compileScs scs) codegen
|
llvmIrToString . instructions <$> execStateT (compileScs scs) codegen
|
||||||
|
|
||||||
compileScs :: [Bind] -> CompilerState ()
|
compileScs :: [Bind] -> CompilerState ()
|
||||||
compileScs [] = pure ()
|
compileScs [] = do
|
||||||
compileScs (Bind (name, t) args exp : xs) = do
|
return ()
|
||||||
|
-- c <- gets (Map.toList . constructors)
|
||||||
|
-- mapM_ (\((id, t), fi) -> do
|
||||||
|
-- emit $ Define FastCC (type2LlvmType t) id []
|
||||||
|
-- emit DefineEnd
|
||||||
|
-- ) c
|
||||||
|
compileScs (Bind (name, _t) args exp : xs) = do
|
||||||
emit $ UnsafeRaw "\n"
|
emit $ UnsafeRaw "\n"
|
||||||
emit . Comment $ show name <> ": " <> show exp
|
emit . Comment $ show name <> ": " <> show exp
|
||||||
let args' = map (second type2LlvmType) args
|
let args' = map (second type2LlvmType) args
|
||||||
|
|
@ -128,8 +148,16 @@ compileScs (Bind (name, t) args exp : xs) = do
|
||||||
emit DefineEnd
|
emit DefineEnd
|
||||||
modify $ \s -> s { variableCount = 0 }
|
modify $ \s -> s { variableCount = 0 }
|
||||||
compileScs xs
|
compileScs xs
|
||||||
where
|
compileScs (DataStructure id@(Ident outer_id) ts : xs) = do
|
||||||
t_return = snd $ partitionType (length args) t
|
let biggest_variant = maximum ((\(_, t) -> sum $ typeByteSize . type2LlvmType <$> t) <$> ts)
|
||||||
|
emit $ Type id [I8, Array biggest_variant I8]
|
||||||
|
mapM_ (\(Ident inner_id, fi) -> do
|
||||||
|
emit $ Type (Ident $ outer_id <> "_" <> inner_id) (I8 : map type2LlvmType fi)
|
||||||
|
) ts
|
||||||
|
compileScs xs
|
||||||
|
|
||||||
|
-- where
|
||||||
|
-- _t_return = snd $ partitionType (length args) t
|
||||||
|
|
||||||
mainContent :: LLVMValue -> [LLVMIr]
|
mainContent :: LLVMValue -> [LLVMIr]
|
||||||
mainContent var =
|
mainContent var =
|
||||||
|
|
@ -150,7 +178,9 @@ mainContent var =
|
||||||
]
|
]
|
||||||
|
|
||||||
defaultStart :: [LLVMIr]
|
defaultStart :: [LLVMIr]
|
||||||
defaultStart = [ UnsafeRaw "@.str = private unnamed_addr constant [3 x i8] c\"%i\n\", align 1\n"
|
defaultStart = [ UnsafeRaw "target triple = \"x86_64-pc-linux-gnu\"\n"
|
||||||
|
, UnsafeRaw "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"
|
||||||
|
, UnsafeRaw "@.str = private unnamed_addr constant [3 x i8] c\"%i\n\", align 1\n"
|
||||||
, UnsafeRaw "declare i32 @printf(ptr noalias nocapture, ...)\n"
|
, UnsafeRaw "declare i32 @printf(ptr noalias nocapture, ...)\n"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -183,19 +213,6 @@ emitECased t e cases = do
|
||||||
emit $ SetVariable (Ident $ show res) (Load ty Ptr (Ident $ show stackPtr))
|
emit $ SetVariable (Ident $ show res) (Load ty Ptr (Ident $ show stackPtr))
|
||||||
where
|
where
|
||||||
emitCases :: LLVMType -> Ident -> Integer -> LLVMValue -> Case -> CompilerState ()
|
emitCases :: LLVMType -> Ident -> Integer -> LLVMValue -> Case -> CompilerState ()
|
||||||
emitCases ty label stackPtr vs (Case (GA.CInt 0) exp) = do
|
|
||||||
ns <- getNewVar
|
|
||||||
lbl_failPos <- (\x -> Ident $ "failed_" <> show x) <$> getNewLabel
|
|
||||||
lbl_succPos <- (\x -> Ident $ "success_" <> show x) <$> getNewLabel
|
|
||||||
lbl_failNeg <- (\x -> Ident $ "failed_" <> show x) <$> getNewLabel
|
|
||||||
lbl_succNeg <- (\x -> Ident $ "success_" <> show x) <$> getNewLabel
|
|
||||||
emit $ SetVariable (Ident $ show ns) (Icmp LLEq ty vs (VInteger 0))
|
|
||||||
emit $ BrCond (VIdent (Ident $ show ns) ty) lbl_succPos lbl_failPos
|
|
||||||
emit $ Label lbl_succPos
|
|
||||||
val <- exprToValue exp
|
|
||||||
emit $ Store ty val Ptr (Ident . show $ stackPtr)
|
|
||||||
emit $ Br label
|
|
||||||
emit $ Label lbl_failPos
|
|
||||||
emitCases ty label stackPtr vs (Case (GA.CInt i) exp) = do
|
emitCases ty label stackPtr vs (Case (GA.CInt i) exp) = do
|
||||||
ns <- getNewVar
|
ns <- getNewVar
|
||||||
lbl_failPos <- (\x -> Ident $ "failed_" <> show x) <$> getNewLabel
|
lbl_failPos <- (\x -> Ident $ "failed_" <> show x) <$> getNewLabel
|
||||||
|
|
@ -342,7 +359,7 @@ type2LlvmType = \case
|
||||||
TFun t xs -> do
|
TFun t xs -> do
|
||||||
let (t', xs') = function2LLVMType xs [type2LlvmType t]
|
let (t', xs') = function2LLVMType xs [type2LlvmType t]
|
||||||
Function t' xs'
|
Function t' xs'
|
||||||
t -> CustomType $ Ident ("\"" ++ show t ++ "\"")
|
TPol t -> CustomType t
|
||||||
where
|
where
|
||||||
function2LLVMType :: Type -> [LLVMType] -> (LLVMType, [LLVMType])
|
function2LLVMType :: Type -> [LLVMType] -> (LLVMType, [LLVMType])
|
||||||
function2LLVMType (TFun t xs) s = function2LLVMType xs (type2LlvmType t : s)
|
function2LLVMType (TFun t xs) s = function2LLVMType xs (type2LlvmType t : s)
|
||||||
|
|
@ -363,3 +380,14 @@ valueGetType (VInteger _) = I64
|
||||||
valueGetType (VIdent _ t) = t
|
valueGetType (VIdent _ t) = t
|
||||||
valueGetType (VConstant s) = Array (length s) I8
|
valueGetType (VConstant s) = Array (length s) I8
|
||||||
valueGetType (VFunction _ _ t) = t
|
valueGetType (VFunction _ _ t) = t
|
||||||
|
|
||||||
|
typeByteSize :: LLVMType -> Int
|
||||||
|
typeByteSize I1 = 1
|
||||||
|
typeByteSize I8 = 1
|
||||||
|
typeByteSize I32 = 4
|
||||||
|
typeByteSize I64 = 8
|
||||||
|
typeByteSize Ptr = 8
|
||||||
|
typeByteSize (Ref _) = 8
|
||||||
|
typeByteSize (Function _ _) = 8
|
||||||
|
typeByteSize (Array n t) = n * typeByteSize t
|
||||||
|
typeByteSize (CustomType _) = 8
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ instance Show LLVMType where
|
||||||
Ref ty -> show ty <> "*"
|
Ref ty -> show ty <> "*"
|
||||||
Function t xs -> show t <> " (" <> intercalate ", " (map show xs) <> ")*"
|
Function t xs -> show t <> " (" <> intercalate ", " (map show xs) <> ")*"
|
||||||
Array n ty -> concat ["[", show n, " x ", show ty, "]"]
|
Array n ty -> concat ["[", show n, " x ", show ty, "]"]
|
||||||
CustomType (Ident ty) -> ty
|
CustomType (Ident ty) -> "%" <> ty
|
||||||
|
|
||||||
data LLVMComp
|
data LLVMComp
|
||||||
= LLEq
|
= LLEq
|
||||||
|
|
@ -146,9 +146,9 @@ llvmIrToString = go 0
|
||||||
replicate i '\t' <> case l of
|
replicate i '\t' <> case l of
|
||||||
(Type (Ident n) types) ->
|
(Type (Ident n) types) ->
|
||||||
concat
|
concat
|
||||||
[ "%", n, " = {"
|
[ "%", n, " = type { "
|
||||||
, intercalate " , " (map show types)
|
, intercalate ", " (map show types)
|
||||||
, "}"
|
, " }\n"
|
||||||
]
|
]
|
||||||
(Define c t (Ident i) params) ->
|
(Define c t (Ident i) params) ->
|
||||||
concat
|
concat
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ data Case = Case GA.Case Exp
|
||||||
|
|
||||||
type Id = (Ident, Type)
|
type Id = (Ident, Type)
|
||||||
|
|
||||||
data Bind = Bind Id [Id] Exp
|
data Bind = Bind Id [Id] Exp | DataStructure Ident [(Ident, [Type])]
|
||||||
deriving (C.Eq, C.Ord, C.Show, C.Read)
|
deriving (C.Eq, C.Ord, C.Show, C.Read)
|
||||||
|
|
||||||
instance Print Program where
|
instance Print Program where
|
||||||
|
|
@ -45,6 +45,12 @@ instance Print Bind where
|
||||||
, doc $ showString "="
|
, doc $ showString "="
|
||||||
, prt 0 rhs
|
, prt 0 rhs
|
||||||
]
|
]
|
||||||
|
prt i (DataStructure (Ident n) xs) = prPrec i 0 $ concatD
|
||||||
|
[ prt 0 n
|
||||||
|
, doc $ showString "{"
|
||||||
|
, doc . showString . show $ xs
|
||||||
|
, doc $ showString "}"
|
||||||
|
]
|
||||||
|
|
||||||
instance Print [Bind] where
|
instance Print [Bind] where
|
||||||
prt _ [] = concatD []
|
prt _ [] = concatD []
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue