X-Git-Url: https://git.lukelau.me/?p=kaleidoscope-hs-old.git;a=blobdiff_plain;f=Main.hs;h=eba1ce1c7ae6e8072b4e78862c2daf750280bdd4;hp=f721911af3da8488e855ca46c966b736da2a5440;hb=e9d3bf0386f5654857fe6eaabe74ca651f9df76d;hpb=882cd77116f1f1688022e69a469b62f97a831725 diff --git a/Main.hs b/Main.hs index f721911..eba1ce1 100644 --- a/Main.hs +++ b/Main.hs @@ -1,12 +1,16 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} module Main where import qualified AST +import Control.Monad +import Control.Monad.Trans.Class import qualified Data.Map as Map import qualified Data.Text.Lazy.IO as Text import Data.String import Foreign.Ptr +import System.Exit import System.IO import LLVM.Context import LLVM.ExecutionEngine @@ -16,41 +20,72 @@ import LLVM.IRBuilder import LLVM.AST.AddrSpace import LLVM.AST.Constant import LLVM.AST.Float +import LLVM.AST.FloatingPointPredicate hiding (False, True) import LLVM.AST.Operand import LLVM.AST.Type as Type +import LLVM.AST.Typed import LLVM.Pretty -import Control.Monad + +type ModuleBuilderE = ModuleBuilderT (Either String) foreign import ccall "dynamic" exprFun :: FunPtr (IO Float) -> IO Float main :: IO () main = do AST.Program asts <- read <$> getContents - let mdl = buildModule "main" $ mapM buildAST asts - withContext $ \ctx -> + let eitherMdl = buildModuleT "main" $ mapM buildAST asts + case eitherMdl of + Left err -> die err + Right mdl -> withContext $ \ctx -> do + hPutStrLn stderr "Before optimisation:" + Text.hPutStrLn stderr (ppllvm mdl) withMCJIT ctx Nothing Nothing Nothing Nothing $ \mcjit -> withModuleFromAST ctx mdl $ \mdl' -> withPassManager defaultCuratedPassSetSpec $ \pm -> do runPassManager pm mdl' >>= guard + hPutStrLn stderr "After optimisation:" Text.hPutStrLn stderr . ppllvm =<< moduleAST mdl' withModuleInEngine mcjit mdl' $ \emdl -> do Just f <- getFunction emdl "expr" let f' = castFunPtr f :: FunPtr (IO Float) exprFun f' >>= print -buildAST :: AST.AST -> ModuleBuilder Operand +evalProg :: AST.Program -> IO (Maybe Float) +evalProg (AST.Program asts) = do + let eitherMdl = buildModuleT "main" $ mapM buildAST asts + case eitherMdl of + Left _ -> return Nothing + Right mdl -> withContext $ \ctx -> + withMCJIT ctx Nothing Nothing Nothing Nothing $ \mcjit -> + withModuleFromAST ctx mdl $ \mdl' -> + withModuleInEngine mcjit mdl' $ \emdl -> do + Just f <- getFunction emdl "expr" + let f' = castFunPtr f :: FunPtr (IO Float) + Just <$> exprFun f' + +-- | Builds up programs at the top-level of an LLVM Module +-- >>> evalProg (read "31 - 5") +-- Just 26.0 +buildAST :: AST.AST -> ModuleBuilderE Operand buildAST (AST.Function nameStr paramStrs body) = do - let name = fromString nameStr - function name params float $ \binds -> do + let n = fromString nameStr + function n params float $ \binds -> do let bindMap = Map.fromList (zip paramStrs binds) buildExpr bindMap body >>= ret where params = zip (repeat float) (map fromString paramStrs) buildAST (AST.Eval e) = function "expr" [] float $ \_ -> buildExpr mempty e >>= ret -buildExpr :: Map.Map String Operand -> AST.Expr -> IRBuilderT ModuleBuilder Operand +-- | Builds up expressions, which are operands in LLVM IR +-- >>> evalProg (read "def foo(x) x * 2; foo(6)") +-- Just 12.0 +-- >>> evalProg (read "if 3 > 2 then 42 else 12") +-- Just 42.0 +buildExpr :: Map.Map String Operand -> AST.Expr -> IRBuilderT ModuleBuilderE Operand buildExpr _ (AST.Num a) = pure $ ConstantOperand (Float (Single a)) -buildExpr binds (AST.Var name) = pure $ binds Map.! name +buildExpr binds (AST.Var n) = case binds Map.!? n of + Just x -> pure x + Nothing -> lift $ lift $ Left $ "'" <> n <> "' doesn't exist in scope" buildExpr binds (AST.Call nameStr params) = do paramOps <- mapM (buildExpr binds) params @@ -68,4 +103,25 @@ buildExpr binds (AST.BinOp op a b) = do AST.Add -> fadd AST.Sub -> fsub AST.Mul -> fmul + AST.Cmp GT -> fcmp OGT + AST.Cmp LT -> fcmp OLT + AST.Cmp EQ -> fcmp OEQ instr va vb + +buildExpr binds (AST.If cond thenE elseE) = mdo + _ifB <- block `named` "if" + + condV <- buildExpr binds cond + when (typeOf condV /= i1) $ lift $ lift $ Left "Not a boolean" + condBr condV thenB elseB + + thenB <- block `named` "then" + thenOp <- buildExpr binds thenE + br mergeB + + elseB <- block `named` "else" + elseOp <- buildExpr binds elseE + br mergeB + + mergeB <- block `named` "ifcont" + phi [(thenOp, thenB), (elseOp, elseB)]