Types for data types are now created.

This commit is contained in:
Samuel Hammersberg 2023-02-24 16:05:49 +01:00
parent 272fbe3504
commit 262543931c
3 changed files with 94 additions and 60 deletions

View file

@ -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

View file

@ -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

View file

@ -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 []