Start new LLVM generator using IRBuilder

pull/21/head
Ethan Reece 2023-09-23 23:15:11 -05:00
parent d42de52f78
commit 9f9642347b
Signed by: me
GPG Key ID: D3993665FF92E1C3
12 changed files with 126 additions and 67 deletions

View File

@ -1,6 +1,6 @@
# Really Bad Compiler in Haskell # Really Bad Compiler in Haskell
A compiler written in Haskell which can currently perform basic arithmetic. Currently using the megaparsec and llvm-hs libraries, but I plan to reimplement parsing and llvm generation myself. Built for the Introduction to Compiler Design class at The University of Texas at Dallas. A compiler written in Haskell which can currently perform basic arithmetic. Currently using the megaparsec and llvm-hs-\* libraries, but I plan to reimplement parsing and llvm generation myself. Built for the Introduction to Compiler Design class at The University of Texas at Dallas.
Main repo: https://git.sudoer.ch/me/really-bad-compiler-in-haskell Main repo: https://git.sudoer.ch/me/really-bad-compiler-in-haskell
@ -27,19 +27,22 @@ Main repo: https://git.sudoer.ch/me/really-bad-compiler-in-haskell
### Learning Resources Used ### Learning Resources Used
- Introduction to Compiler Design class at The University of Texas at Dallas, taught by Charles Averill - Introduction to Compiler Design class at The University of Texas at Dallas, taught by Charles Averill
- learnyouahaskell.com (for learning Haskell basics) - https://learnyouahaskell.com (for learning Haskell basics)
- https://akashagrawal.me/2017/01/19/beginners-guide-to-megaparsec.html - https://akashagrawal.me/2017/01/19/beginners-guide-to-megaparsec.html
- https://markkarpov.com/tutorial/megaparsec.html (for help writing a Haskell equation parser) - https://markkarpov.com/tutorial/megaparsec.html (for help writing a Haskell equation parser using megaparsec)
- https://www.forth.com/starting-forth/1-forth-stacks-dictionary/ (for learning Forth) - https://www.forth.com/starting-forth/1-forth-stacks-dictionary/ (for learning Forth)
- https://blog.josephmorag.com/posts/mcc0/ (Haskell compiler tutorial with megaparsec, llvm-hs, and nix) - https://blog.josephmorag.com/posts/mcc0/ (Haskell compiler tutorial with megaparsec, llvm-hs, and nix)
- https://gh.sudoer.ch/llvm-hs/llvm-hs-examples (for help writing an llvm code generator) - https://gh.sudoer.ch/llvm-hs/llvm-hs-examples (for help writing an llvm code generator using llvm-hs)
- https://danieljharvey.github.io/posts/2023-02-08-llvm-compiler-part-1.html (for help using llvm-hs-pure)
- https://gh.sudoer.ch/danieljharvey/mimsa/blob/trunk/llvm-calc/src/Calc/Compile/ToLLVM.hs (source code for above resource)
- https://9to5tutorial.com/homebrew-compiler-made-with-haskell-llvm-configuration (for help using llvm-hs-pure)
### Tools ### Tools
- Language: Haskell - Language: Haskell
- Haskell tools: GHCup, Stack, Cabal - Haskell tools: GHCup, Stack, Cabal, GHC 9.2
- Libraries: megaparsec, parser-combinators, text, llvm-hs-pure - Libraries: megaparsec, parser-combinators, text, llvm-hs-pure 15, llvm-hs-pretty-15
- Dependencies: llvm, clang - Dependencies: llvm 15, clang 15
- IDE: VSCodium - IDE: VSCodium
- Git platform: Forgejo - Git platform: Forgejo
- AI: Phind (GPT-4), ollama (codellama) - AI: Phind (GPT-4), ollama (codellama)

View File

@ -1,6 +1,6 @@
module Eval.Expression (evalExpr) where module Eval.Expr (evalExpr) where
import Objects.Expression import Types.Expr
eval :: Expr -> Int eval :: Expr -> Int
eval (Lit x) = x eval (Lit x) = x

View File

@ -0,0 +1,57 @@
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
-- see https://gh.sudoer.ch/danieljharvey/mimsa/blob/trunk/llvm-calc/src/Calc/Compile/ToLLVM.hs
module LLVMGen.Expr (getLLVMStr) where
import Data.Text.Lazy
import LLVM.AST hiding (function)
import LLVM.AST.Type
import LLVM.IRBuilder.Constant
import LLVM.IRBuilder.Instruction
import LLVM.IRBuilder.Module
import LLVM.IRBuilder.Monad
import LLVM.Pretty
import Types.Expr as Expr
-- charStar :: LLVM.Type
-- charStar = LLVM.ptr LLVM.i8
getLLVM :: Expr -> Module
getLLVM expr =
buildModule "program" $ do
-- TODO: better naming
printf <- externVarArgs "printf" [ptr] i32 -- or LLVM.ptr LLVM.i8
let numFormatStr = globalStringPtr "%d\n" (mkName "str")
function "main" [] i32 $ \_ -> do
ourExpression <- exprToLLVM expr
nfs <- numFormatStr
_ <- call i32 printf [(ConstantOperand nfs, []), (ourExpression, [])]
ret (int32 0)
exprToLLVM ::
( MonadIRBuilder m,
MonadModuleBuilder m
) =>
Expr ->
m Operand
exprToLLVM (Lit prim) = pure $ primToLLVM prim
exprToLLVM (Expr.Add a b) = do
lhs <- exprToLLVM a
rhs <- exprToLLVM b
add lhs rhs
exprToLLVM (Expr.Sub a b) = do
lhs <- exprToLLVM a
rhs <- exprToLLVM b
sub lhs rhs
exprToLLVM (Expr.Mul a b) = do
lhs <- exprToLLVM a
rhs <- exprToLLVM b
mul lhs rhs
primToLLVM :: Int -> Operand
primToLLVM i = int32 (fromIntegral i)
getLLVMStr :: Expr -> Text
getLLVMStr expr = ppllvm (getLLVM expr)

View File

@ -1,6 +1,6 @@
module LLVMGen.Expression (getLLVM) where module LLVMGen.Expr (getLLVM) where
import qualified Objects.Expression as Expr import qualified Objects.Expr as Expr
import LLVM.AST import LLVM.AST
import qualified LLVM.AST as AST import qualified LLVM.AST as AST
@ -28,7 +28,13 @@ defMain = GlobalDefinition functionDefaults
where where
body = BasicBlock body = BasicBlock
(Name "entry") (Name "entry")
[] [ Name "calltmp" :=
Call
{ tailCallKind = Nothing
, function = Right (ConstantOperand (GlobalReference (PointerType (FunctionType int [int, int] False) defaultAddrSpace) (Name "add")))
, arguments = [ (ConstantOperand (Int 32 10), []), (ConstantOperand (Int 32 20), []) ]
}
]
(Do $ Ret (Just (ConstantOperand (Int 32 0))) []) (Do $ Ret (Just (ConstantOperand (Int 32 0))) [])
defAdd :: Definition defAdd :: Definition
@ -52,7 +58,6 @@ defAdd = GlobalDefinition functionDefaults
[]] []]
(Do $ Ret (Just (LocalReference int (Name "result"))) []) (Do $ Ret (Just (LocalReference int (Name "result"))) [])
module_ :: AST.Module module_ :: AST.Module
module_ = defaultModule module_ = defaultModule
{ moduleName = "basic" { moduleName = "basic"

View File

@ -1,24 +1,25 @@
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where module Main (main) where
import Control.Monad import Data.Text.Lazy.IO qualified as T
import Data.Either import Eval.Expr
import Eval.Expression import LLVMGen.Expr
import Objects.Expression import Parser.Expr
import Parser.Expression
import System.Environment import System.Environment
import LLVMGen.Expression import Types.Expr
import System.IO
import Text.Megaparsec
getRight :: ParseResult -> Expr getRight :: ParseResult -> Expr
getRight (Right r) = r getRight (Right r) = r
getResult :: String -> Int getResult :: String -> Int
getResult str = evalExpr (getRight (parseExpr str)) getResult str = evalExpr (getRight (parseExpr str)) -- TODO: add error messages
main :: IO ()
main = do main = do
fileName <- fmap head getArgs fileName <- fmap head getArgs
contents <- readFile fileName contents <- readFile fileName
let result = getResult contents let result = getResult contents
print result print result
getLLVM T.putStrLn (getLLVMStr (getRight (parseExpr contents)))

View File

@ -1,19 +0,0 @@
module Objects.Expression
( Expr
( Lit,
Add,
Sub,
Mul,
Div
),
-- solve,
)
where
data Expr
= Lit Int
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
deriving (Show)

View File

@ -1,11 +1,15 @@
module Parser.Expression (parseExpr, ParseResult) where -- see https://markkarpov.com/tutorial/megaparsec.html
{-# LANGUAGE ImportQualifiedPost #-}
module Parser.Expr (parseExpr, ParseResult) where
import Control.Monad.Combinators.Expr import Control.Monad.Combinators.Expr
import Data.Functor.Identity qualified
import Data.Void (Void) import Data.Void (Void)
import Objects.Expression
import Text.Megaparsec as MP import Text.Megaparsec as MP
import Text.Megaparsec.Char as C import Text.Megaparsec.Char as C
import Text.Megaparsec.Char.Lexer as L import Text.Megaparsec.Char.Lexer as L
import Types.Expr
type Parser = Parsec Void String type Parser = Parsec Void String
@ -31,6 +35,7 @@ table =
] ]
] ]
binaryOp :: String -> (a -> a -> a) -> Operator (ParsecT Void String Data.Functor.Identity.Identity) a
binaryOp name f = InfixL (f <$ symbolParser name) binaryOp name f = InfixL (f <$ symbolParser name)
expr :: Parser Expr expr :: Parser Expr

View File

@ -0,0 +1,9 @@
module Types.Expr (Expr (..)) where
data Expr
= Lit Int
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
deriving (Show)

View File

@ -6,9 +6,9 @@ dependencies:
- megaparsec >= 9.0.1 && < 10 - megaparsec >= 9.0.1 && < 10
- parser-combinators - parser-combinators
- text - text
- llvm-hs >= 15 && < 16 # - llvm-hs >= 15 && < 16
- llvm-hs-pure >= 15 && < 16 - llvm-hs-pure >= 15 && < 16
# - llvm-hs-pretty >= 15 && < 16 - llvm-hs-pretty >= 15 && < 16
- bytestring - bytestring
tested-with: GHC == 9.2.8 tested-with: GHC == 9.2.8
category: Compilers/Interpreters category: Compilers/Interpreters

View File

@ -16,10 +16,10 @@ tested-with:
executable really-bad-compiler-in-haskell executable really-bad-compiler-in-haskell
main-is: Main.hs main-is: Main.hs
other-modules: other-modules:
Eval.Expression Eval.Expr
LLVMGen.Expression LLVMGen.Expr
Objects.Expression Parser.Expr
Parser.Expression Types.Expr
Paths_really_bad_compiler_in_haskell Paths_really_bad_compiler_in_haskell
hs-source-dirs: hs-source-dirs:
main main
@ -29,7 +29,7 @@ executable really-bad-compiler-in-haskell
build-depends: build-depends:
base >=4.14.3 && <5 base >=4.14.3 && <5
, bytestring , bytestring
, llvm-hs ==15.* , llvm-hs-pretty ==15.*
, llvm-hs-pure ==15.* , llvm-hs-pure ==15.*
, megaparsec >=9.0.1 && <10 , megaparsec >=9.0.1 && <10
, parser-combinators , parser-combinators

View File

@ -3,13 +3,13 @@ resolver: lts-20.26
packages: packages:
- . - .
extra-deps: extra-deps:
# - github: hyunsooda/llvm-hs-pretty-15 - github: hyunsooda/llvm-hs-pretty-15
# commit: 79283942d1667168ecd65237667aff7fed730303 commit: 79283942d1667168ecd65237667aff7fed730303
- github: llvm-hs/llvm-hs - github: llvm-hs/llvm-hs
commit: 5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76 commit: 5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76
subdirs: subdirs:
- llvm-hs-pure - llvm-hs-pure
- llvm-hs # - llvm-hs
nix: nix:
enable: true enable: true
packages: [llvm_15, clang_15, libxml2] packages: [llvm_15, clang_15, libxml2]

View File

@ -4,6 +4,17 @@
# https://docs.haskellstack.org/en/stable/lock_files # https://docs.haskellstack.org/en/stable/lock_files
packages: packages:
- completed:
name: llvm-hs-pretty
pantry-tree:
sha256: 22ac4a47e1833dece52af7a6f8589958021d67292f6cc3de015ecb7c699db62d
size: 5197
sha256: 8348b72a61807414ad15e0b7e82a7753e4473701e7ab98520c2e9d9a51c5ed7f
size: 43787
url: https://github.com/hyunsooda/llvm-hs-pretty-15/archive/79283942d1667168ecd65237667aff7fed730303.tar.gz
version: 15.0.0
original:
url: https://github.com/hyunsooda/llvm-hs-pretty-15/archive/79283942d1667168ecd65237667aff7fed730303.tar.gz
- completed: - completed:
name: llvm-hs-pure name: llvm-hs-pure
pantry-tree: pantry-tree:
@ -17,19 +28,6 @@ packages:
original: original:
subdir: llvm-hs-pure subdir: llvm-hs-pure
url: https://github.com/llvm-hs/llvm-hs/archive/5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76.tar.gz url: https://github.com/llvm-hs/llvm-hs/archive/5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76.tar.gz
- completed:
name: llvm-hs
pantry-tree:
sha256: 21f74a6f51fae6c0a0fcf3e6620a59f341289ac743998b41ed3276fd1b7d8862
size: 12716
sha256: 526b67e2da9ce25b3856c221b6772e699a7593dbb5ba38e7ee2436349de70966
size: 9802209
subdir: llvm-hs
url: https://github.com/llvm-hs/llvm-hs/archive/5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76.tar.gz
version: 15.0.0
original:
subdir: llvm-hs
url: https://github.com/llvm-hs/llvm-hs/archive/5bca2c1a2a3aa98ecfb19181e7a5ebbf3e212b76.tar.gz
snapshots: snapshots:
- completed: - completed:
sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2 sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2