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
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
@ -27,19 +27,22 @@ Main repo: https://git.sudoer.ch/me/really-bad-compiler-in-haskell
### Learning Resources Used
- 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://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://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
- Language: Haskell
- Haskell tools: GHCup, Stack, Cabal
- Libraries: megaparsec, parser-combinators, text, llvm-hs-pure
- Dependencies: llvm, clang
- Haskell tools: GHCup, Stack, Cabal, GHC 9.2
- Libraries: megaparsec, parser-combinators, text, llvm-hs-pure 15, llvm-hs-pretty-15
- Dependencies: llvm 15, clang 15
- IDE: VSCodium
- Git platform: Forgejo
- 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 (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 qualified LLVM.AST as AST
@ -28,7 +28,13 @@ defMain = GlobalDefinition functionDefaults
where
body = BasicBlock
(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))) [])
defAdd :: Definition
@ -52,7 +58,6 @@ defAdd = GlobalDefinition functionDefaults
[]]
(Do $ Ret (Just (LocalReference int (Name "result"))) [])
module_ :: AST.Module
module_ = defaultModule
{ moduleName = "basic"

View File

@ -1,24 +1,25 @@
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Control.Monad
import Data.Either
import Eval.Expression
import Objects.Expression
import Parser.Expression
import Data.Text.Lazy.IO qualified as T
import Eval.Expr
import LLVMGen.Expr
import Parser.Expr
import System.Environment
import LLVMGen.Expression
import System.IO
import Text.Megaparsec
import Types.Expr
getRight :: ParseResult -> Expr
getRight (Right r) = r
getResult :: String -> Int
getResult str = evalExpr (getRight (parseExpr str))
getResult str = evalExpr (getRight (parseExpr str)) -- TODO: add error messages
main :: IO ()
main = do
fileName <- fmap head getArgs
contents <- readFile fileName
let result = getResult contents
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 Data.Functor.Identity qualified
import Data.Void (Void)
import Objects.Expression
import Text.Megaparsec as MP
import Text.Megaparsec.Char as C
import Text.Megaparsec.Char.Lexer as L
import Types.Expr
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)
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
- parser-combinators
- text
- llvm-hs >= 15 && < 16
# - llvm-hs >= 15 && < 16
- llvm-hs-pure >= 15 && < 16
# - llvm-hs-pretty >= 15 && < 16
- llvm-hs-pretty >= 15 && < 16
- bytestring
tested-with: GHC == 9.2.8
category: Compilers/Interpreters

View File

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

View File

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

View File

@ -4,6 +4,17 @@
# https://docs.haskellstack.org/en/stable/lock_files
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:
name: llvm-hs-pure
pantry-tree:
@ -17,19 +28,6 @@ packages:
original:
subdir: llvm-hs-pure
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:
- completed:
sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2