├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── docker-compose.yml ├── ejemplos.md ├── hlint.yaml ├── kaleidoscope ├── .dockerignore ├── .hlint.yaml ├── CHANGELOG.md ├── cabal.project ├── examples │ ├── Example.hs │ ├── IRBuilderExamples.hs │ ├── _multi_instr.k │ ├── id_with_print.ll │ ├── llvm_ast │ └── llvm_example │ │ ├── example.ll │ │ ├── hello.c │ │ └── list.ll ├── kaleidoscope-fing.cabal ├── out.ll ├── src │ ├── CLIParameters.hs │ ├── CodeGen │ │ ├── GenModule.hs │ │ ├── GenOperand.hs │ │ ├── JIT.hs │ │ ├── LocalVar.hs │ │ └── Utils │ │ │ └── Types.hs │ ├── Main.hs │ ├── Parser │ │ ├── Lexer.hs │ │ └── Parse.hs │ ├── Processor.hs │ ├── StdLib │ │ ├── BaseDefs.hs │ │ ├── GenLibs.hs │ │ └── lib │ │ │ └── list.k │ └── Syntax.hs └── test │ ├── Spec.hs │ ├── generator │ ├── GenPrograms.hs │ ├── generator.md │ └── iterate.sh │ ├── output │ ├── add_float_float.k │ ├── add_float_int.k │ ├── add_int_float.k │ ├── add_int_int.k │ ├── and_false_false.k │ ├── and_false_true.k │ ├── and_true_false.k │ ├── and_true_true.k │ ├── cons_add.k │ ├── cons_function.k │ ├── cons_functions.k │ ├── cons_int.k │ ├── const_float.k │ ├── const_int_float.k │ ├── const_int_int.k │ ├── cos.k │ ├── div_float_int.k │ ├── div_int_int.k │ ├── double_to_int.k │ ├── extern.k │ ├── fabs.k │ ├── fn_add_float_float.k │ ├── fn_add_float_int.k │ ├── fn_add_int_int.k │ ├── fn_create_list_bool.k │ ├── fn_create_list_float.k │ ├── fn_create_list_int.k │ ├── fn_div_int_int.k │ ├── fn_int_float.k │ ├── fn_nested.k │ ├── fn_return_tuple.k │ ├── fn_return_tuple_nested.k │ ├── foldl_int.k │ ├── foldr_int.k │ ├── fst_float.k │ ├── fst_int.k │ ├── fst_tuple.k │ ├── head_bool.k │ ├── head_float.k │ ├── head_int.k │ ├── higher_order_bool.k │ ├── higher_order_float.k │ ├── higher_order_int.k │ ├── if_float.k │ ├── if_int.k │ ├── if_nested.k │ ├── int_to_double.k │ ├── let_in_float.k │ ├── let_in_int.k │ ├── let_in_multiple.k │ ├── let_in_nested.k │ ├── list_all_false.k │ ├── list_all_true.k │ ├── list_bool.k │ ├── list_filter_int.k │ ├── list_float.k │ ├── list_int.k │ ├── list_int_constant.k │ ├── list_int_function.k │ ├── list_map_int.k │ ├── list_max.k │ ├── list_nth_int.k │ ├── list_reverse_int.k │ ├── log.k │ ├── negative_integer.k │ ├── not_false.k │ ├── not_true.k │ ├── or_false_false.k │ ├── or_false_true.k │ ├── or_true_false.k │ ├── or_true_true.k │ ├── primes.k │ ├── recursive_fib.k │ ├── recursive_sum.k │ ├── redefinition_function.k │ ├── redefinition_function_recursive.k │ ├── sin.k │ ├── snd_bool.k │ ├── snd_float.k │ ├── snd_tuple.k │ ├── tail_bool.k │ ├── tail_float.k │ ├── tail_int.k │ ├── tan.k │ ├── tuple_max.k │ └── tuple_nested.k │ └── programs │ ├── add_float_float.k │ ├── add_float_int.k │ ├── add_int_float.k │ ├── add_int_int.k │ ├── and_false_false.k │ ├── and_false_true.k │ ├── and_true_false.k │ ├── and_true_true.k │ ├── cons_add.k │ ├── cons_function.k │ ├── cons_functions.k │ ├── cons_int.k │ ├── cos.k │ ├── div_float_int.k │ ├── div_int_int.k │ ├── double_to_int.k │ ├── extern.k │ ├── fabs.k │ ├── fn_add_float_float.k │ ├── fn_add_float_int.k │ ├── fn_add_int_int.k │ ├── fn_create_list_bool.k │ ├── fn_create_list_float.k │ ├── fn_create_list_int.k │ ├── fn_div_int_int.k │ ├── fn_int_float.k │ ├── fn_nested.k │ ├── fn_return_tuple.k │ ├── fn_return_tuple_nested.k │ ├── foldl_int.k │ ├── foldr_int.k │ ├── fst_float.k │ ├── fst_int.k │ ├── fst_tuple.k │ ├── head_bool.k │ ├── head_float.k │ ├── head_int.k │ ├── higher_order_bool.k │ ├── higher_order_float.k │ ├── higher_order_int.k │ ├── if_float.k │ ├── if_int.k │ ├── if_nested.k │ ├── int_to_double.k │ ├── let_in_float.k │ ├── let_in_int.k │ ├── let_in_multiple.k │ ├── let_in_nested.k │ ├── list_all_false.k │ ├── list_all_true.k │ ├── list_bool.k │ ├── list_filter_int.k │ ├── list_float.k │ ├── list_int.k │ ├── list_int_function.k │ ├── list_map_int.k │ ├── list_max.k │ ├── list_nth_int.k │ ├── list_reverse_int.k │ ├── log.k │ ├── negative_integer.k │ ├── not_false.k │ ├── not_true.k │ ├── or_false_false.k │ ├── or_false_true.k │ ├── or_true_false.k │ ├── or_true_true.k │ ├── primes.k │ ├── recursive_fib.k │ ├── recursive_sum.k │ ├── redefinition_function.k │ ├── redefinition_function_recursive.k │ ├── sin.k │ ├── snd_bool.k │ ├── snd_float.k │ ├── snd_tuple.k │ ├── tail_bool.k │ ├── tail_float.k │ ├── tail_int.k │ ├── tan.k │ ├── tuple_max.k │ └── tuple_nested.k ├── notas ├── 08-04-2023-dynamic-libraries.md ├── 13-12-2022.md ├── 21-05-2023-interprete.md └── compilacion-ll.md ├── readme.md └── setup-macos.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | !*.* 3 | !*/ 4 | 5 | dist 6 | dist-* 7 | cabal-dev 8 | *.o 9 | *.hi 10 | *.hie 11 | *.chi 12 | *.chs.h 13 | *.dyn_o 14 | *.dyn_hi 15 | .hpc 16 | .hsenv 17 | .cabal-sandbox/ 18 | cabal.sandbox.config 19 | *.prof 20 | *.aux 21 | *.hp 22 | *.eventlog 23 | .stack-work/ 24 | cabal.project.local 25 | cabal.project.local~ 26 | .HTF/ 27 | .ghc.environment.* 28 | 29 | *.s 30 | *.out 31 | out.k 32 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/target": true 4 | } 5 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM haskell:8.10.7-buster 2 | 3 | # Install dependencies 4 | RUN apt-get -qq update \ 5 | && apt-get install -qqy --no-install-recommends \ 6 | # Install tools 7 | bash vim nano \ 8 | # Install LLVM dependencies 9 | gnupg2 ca-certificates apt-transport-https \ 10 | autoconf automake cmake dpkg-dev file make patch libc6-dev \ 11 | # Remove apt cache 12 | && apt-get clean \ 13 | && rm -rf /var/lib/apt/lists/* 14 | 15 | ## Set LLVM repository key 16 | # RUN wget -nv -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 17 | ADD --checksum=sha256:ce6eee4130298f79b0e0f09a89f93c1bc711cd68e7e3182d37c8e96c5227e2f0 \ 18 | https://apt.llvm.org/llvm-snapshot.gpg.key /tmp/llvm-snapshot.gpg.key 19 | RUN apt-key add /tmp/llvm-snapshot.gpg.key 20 | ## Set LLVM repository 21 | RUN echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-12 main" > /etc/apt/sources.list.d/llvm.list; 22 | RUN apt-get -qq update && apt-get install -qqy -t llvm-toolchain-buster-12 clang-12 clang-tidy-12 clang-format-12 lld-12 23 | RUN for f in /usr/lib/llvm-12/bin/*; do ln -sf "$f" /usr/bin; done && rm -rf /var/lib/apt/lists/* 24 | 25 | # Install Haskell Language Server 26 | # RUN wget -nv https://github.com/haskell/haskell-language-server/releases/download/2.2.0.0/haskell-language-server-2.2.0.0-x86_64-linux-deb10.tar.xz && tar xf haskell-language-server-2.2.0.0-x86_64-linux-deb10.tar.xz 27 | ADD --checksum=sha256:a39d15fbb2dc04c6de7f01f9a735930687488e064ea27e0b0b9bb845710d669e \ 28 | https://github.com/haskell/haskell-language-server/releases/download/2.2.0.0/haskell-language-server-2.2.0.0-x86_64-linux-deb10.tar.xz / 29 | RUN tar xf haskell-language-server-2.2.0.0-x86_64-linux-deb10.tar.xz 30 | WORKDIR /haskell-language-server-2.2.0.0 31 | RUN make && make install 32 | 33 | # Update cabal 34 | RUN cabal update && cabal install cabal-install 35 | 36 | WORKDIR /kaleidoscope 37 | 38 | # Add just the .cabal file to capture dependencies 39 | COPY /kaleidoscope/cabal.project /kaleidoscope/kaleidoscope-fing.cabal ./ 40 | 41 | RUN cabal build --only-dependencies -j8 42 | 43 | COPY /kaleidoscope /kaleidoscope 44 | RUN cabal install 45 | 46 | CMD ["bash"] 47 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | project: 3 | build: . 4 | tty: true 5 | stdin_open: true 6 | volumes: 7 | - ./kaleidoscope:/kaleidoscope 8 | - cabal-cache:/root/.cabal 9 | - ghc-cache:/root/.ghc 10 | - apt-cache:/var/cache/apt 11 | 12 | volumes: 13 | cabal-cache: 14 | ghc-cache: 15 | apt-cache: 16 | -------------------------------------------------------------------------------- /ejemplos.md: -------------------------------------------------------------------------------- 1 | `ready> 500;` 2 | 3 | ``` 4 | ; ModuleID = 'my cool jit' 5 | source_filename = "" 6 | 7 | define double @main() { 8 | entry: 9 | ret double 5.000000e+02 10 | } 11 | ``` 12 | 13 | 14 | `ready> def f() 1 + 1;` 15 | 16 | ``` 17 | ; ModuleID = 'my cool jit' 18 | source_filename = "" 19 | 20 | define double @f() { 21 | entry: 22 | %0 = fadd double 1.000000e+00, 1.000000e+00 23 | ret double %0 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /hlint.yaml: -------------------------------------------------------------------------------- 1 | - ignore: { name: ImportQualifiedPost } 2 | -------------------------------------------------------------------------------- /kaleidoscope/.dockerignore: -------------------------------------------------------------------------------- 1 | examples 2 | test 3 | 4 | .hie 5 | dist-newstyle 6 | 7 | CHANGELOG.md 8 | -------------------------------------------------------------------------------- /kaleidoscope/.hlint.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrescollares/kaleidoscope/23463948b25a3bcd565407365b8fffcad7a21e30/kaleidoscope/.hlint.yaml -------------------------------------------------------------------------------- /kaleidoscope/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Revision history for kaleidoscope-fing 2 | 3 | ## 0.1.0.0 -- YYYY-mm-dd 4 | 5 | * First version. Released on an unsuspecting world. 6 | -------------------------------------------------------------------------------- /kaleidoscope/cabal.project: -------------------------------------------------------------------------------- 1 | source-repository-package 2 | type: git 3 | location: https://github.com/llvm-hs/llvm-hs 4 | subdir: 5 | llvm-hs-pure 6 | llvm-hs 7 | tag: 423220bffac4990d019fc088c46c5f25310d5a33 8 | 9 | packages: ./kaleidoscope-fing.cabal 10 | 11 | tests: True -------------------------------------------------------------------------------- /kaleidoscope/examples/Example.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Example where 4 | 5 | import Control.Monad.Except 6 | import Data.ByteString.Char8 as BS 7 | import LLVM.AST 8 | import qualified LLVM.AST as AST 9 | import LLVM.AST.Global 10 | import LLVM.Context 11 | import LLVM.Module 12 | 13 | int :: Type 14 | int = IntegerType 32 15 | 16 | defAdd :: Definition 17 | defAdd = 18 | GlobalDefinition 19 | functionDefaults 20 | { name = Name "add", 21 | parameters = 22 | ( [ Parameter int (Name "a") [], 23 | Parameter int (Name "b") [] 24 | ], 25 | False 26 | ), 27 | returnType = int, 28 | basicBlocks = [body] 29 | } 30 | where 31 | body = 32 | BasicBlock 33 | (Name "entry") 34 | [ Name "result" 35 | := Add 36 | False -- no signed wrap 37 | False -- no unsigned wrap 38 | (LocalReference int (Name "a")) 39 | (LocalReference int (Name "b")) 40 | [] 41 | ] 42 | (Do $ Ret (Just (LocalReference int (Name "result"))) []) 43 | 44 | module_ :: AST.Module 45 | module_ = 46 | defaultModule 47 | { moduleName = "basic", 48 | moduleDefinitions = [defAdd] 49 | } 50 | 51 | toLLVM :: AST.Module -> IO () 52 | toLLVM modl = withContext $ \ctx -> do 53 | llvm <- withModuleFromAST ctx modl moduleLLVMAssembly 54 | BS.putStrLn llvm 55 | 56 | main :: IO () 57 | main = toLLVM module_ 58 | -------------------------------------------------------------------------------- /kaleidoscope/examples/IRBuilderExamples.hs: -------------------------------------------------------------------------------- 1 | genOptimizedMainModuleIR :: IO Module 2 | genOptimizedMainModuleIR = genModule [Float 5.0] 3 | 4 | genSimpleFunction :: IO Module 5 | genSimpleFunction = genModule [S.Function "plus" ["x", "y"] (Float 5.0)] 6 | 7 | genNotSoSimpleFunction :: IO Module 8 | genNotSoSimpleFunction = genModule [S.Function "id" ["x"] (Var "x")] 9 | 10 | genFunctionCall :: IO Module 11 | genFunctionCall = genModule [ 12 | S.Function "one" [] (Float 1.0), 13 | S.Call "one" [] 14 | ] 15 | 16 | genIfFalse :: IO Module 17 | genIfFalse = genModule [S.If (BinOp ">" (Float 0.0) (Float 1.0)) (Float 8.0) (Float 2.0)] 18 | 19 | genIfTrue :: IO Module 20 | genIfTrue = genModule [S.If (Float 1.0) (Float 5.0) (Float 2.0)] 21 | 22 | genRecursive :: IO Module 23 | genRecursive = genModule [ 24 | S.Function "rec" ["x", "y"] (If (BinOp "<" (Var "x") (Float 1.0)) (Var "y") (S.Call "rec" [BinOp "-" (Var "x") (Float 1.0), BinOp "+" (Var "y") (Var "x")])), 25 | S.Call "rec" [Float 5.0, Float 0.0] 26 | ] 27 | 28 | 29 | simple :: Module 30 | simple = buildModule "exampleModule" $ do 31 | function "plus" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 32 | r <- add x y 33 | ret r 34 | 35 | conditional :: Module 36 | conditional = buildModule "conditionModule" $ do 37 | -- This breaks the SSA Principle: https://stackoverflow.com/a/70901888 38 | -- f <- function "f" [(AST.i32, "a")] AST.i32 $ \[a] -> mdo 39 | -- cond <- icmp P.EQ a (ConstantOperand (C.Int 32 0)) 40 | -- condBr cond ifThen ifElse 41 | -- ifThen <- block `named` "if.then" 42 | -- trVal <- add a (ConstantOperand (C.Int 32 0)) 43 | -- ret trVal 44 | -- -- br ifExit 45 | -- ifElse <- block `named` "if.else" 46 | -- flVal <- add a (ConstantOperand (C.Int 32 0)) 47 | -- ret flVal 48 | 49 | f <- function "f" [(ASTType.i32, "a")] ASTType.i32 $ \[a] -> mdo 50 | cond <- icmp P.EQ a (ConstantOperand (C.Int 32 0)) 51 | condBr cond ifThen ifElse 52 | ifThen <- block `named` "if.then" 53 | trVal <- add a (ConstantOperand (C.Int 32 0)) 54 | br ifExit 55 | ifElse <- block `named` "if.else" 56 | flVal <- add a (ConstantOperand (C.Int 32 0)) 57 | br ifExit 58 | ifExit <- block `named` "if.exit" 59 | -- SSA 60 | r <- phi [(trVal, ifThen), (flVal, ifElse)] 61 | ret r 62 | 63 | function "main" [] ASTType.i32 $ \[] -> mdo 64 | -- the empty array are the parameter attributes: https://hackage.haskell.org/package/llvm-hs-pure-9.0.0/docs/LLVM-ASTType.ParameterAttribute.html 65 | r <- call f [(ConstantOperand (C.Int 32 0), [])] 66 | ret r 67 | 68 | arithmetrics :: Module 69 | arithmetrics = buildModule "arithmetrics" $ do 70 | -- function "+" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 71 | -- r <- add x y 72 | -- ret r 73 | 74 | -- function "-" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 75 | -- r <- sub x y 76 | -- ret r 77 | 78 | -- function "*" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 79 | -- r <- mul x y 80 | -- ret r 81 | 82 | -- function "/" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 83 | -- r <- sdiv x y 84 | -- ret r 85 | 86 | function "%" [(ASTType.i32, "x"), (ASTType.i32, "y")] ASTType.i32 $ \[x, y] -> do 87 | _ <- trace (show x) $ pure () 88 | 89 | var <- fresh `named` "x" 90 | r <- srem (LocalReference ASTType.i32 var) y 91 | ret r 92 | 93 | globalDef :: Module 94 | globalDef = buildModule "variable_test" $ do 95 | x <- global "x" ASTType.double (C.Float (F.Double 50.0)) 96 | 97 | function "main" [] ASTType.double $ \[] -> do 98 | x1 <- load (ConstantOperand (GlobalReference (ASTType.ptr ASTType.double) "y")) 0 99 | r <- fadd x1 (ConstantOperand (C.Float (F.Double 1.0))) 100 | -- res <- call (ConstantOperand (C.GlobalReference (ptr (FunctionType ASTType.i32 [ ] False)) (Name "f")) ) [ ] 101 | ret x1 -------------------------------------------------------------------------------- /kaleidoscope/examples/_multi_instr.k: -------------------------------------------------------------------------------- 1 | def binary : 1 (x y) y; 2 | 3 | def circlearea(r) 4 | var pi = 3.14 in 5 | pi * r * r; 6 | 7 | var dos = 10000 in 8 | dos + circlearea(2) : 9 | circlearea(dos); 10 | 11 | # problem 12 | circlearea(1); -------------------------------------------------------------------------------- /kaleidoscope/examples/id_with_print.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'my cool jit' 2 | source_filename = "" 3 | 4 | define double @id(double %x) { 5 | entry: 6 | %0 = alloca double, align 8 7 | store double %x, double* %0, align 8 8 | %1 = load double, double* %0, align 8 9 | ret double %1 10 | } 11 | 12 | ; https://stackoverflow.com/questions/69636349/how-to-print-floats-from-llvm-ir 13 | @.fstr = private unnamed_addr constant [4 x i8] c"%f\0A\00" 14 | 15 | declare i32 @printf(i8*, ...) 16 | 17 | define double @main() { 18 | entry: 19 | %0 = call double @id(double 0x430FEE0B99F3FB98) 20 | %1 = getelementptr [4 x i8],[4 x i8]* @.fstr, i64 0, i64 0 21 | %2 = call i32 (i8*, ...) @printf(i8* %1, double %0) 22 | ret double %0 23 | } -------------------------------------------------------------------------------- /kaleidoscope/examples/llvm_ast: -------------------------------------------------------------------------------- 1 | GlobalDefinition ( 2 | Function {returnType = IntegerType {typeBits = 32}, name = Name "foo", 3 | parameters = ([Parameter (IntegerType {typeBits = 32}) (Name "x_0") []],False), 4 | basicBlocks = [ 5 | BasicBlock (UnName 0) [ 6 | UnName 1 := Mul {nsw = False, nuw = False, operand0 = LocalReference ( 7 | IntegerType {typeBits = 32}) (Name "x_0"), 8 | operand1 = ConstantOperand ( 9 | Int {integerBits = 32, integerValue = 2} 10 | ) 11 | } 12 | ] ( 13 | Do ( Ret {returnOperand = Just ( 14 | LocalReference (IntegerType {typeBits = 32}) (UnName 1) 15 | ), metadata' = []} 16 | ) 17 | )]}) 18 | 19 | 20 | GlobalDefinition ( 21 | Function { returnType = IntegerType {typeBits = 32}, name = Name "main", 22 | parameters = ([], False), 23 | basicBlocks = [ 24 | BasicBlock (UnName 0) [ 25 | UnName 1 := Call { 26 | function = Right (ConstantOperand ( 27 | GlobalReference (PointerType {pointerReferent = FunctionType { 28 | resultType = IntegerType {typeBits = 32}, 29 | argumentTypes = [IntegerType {typeBits = 32}], isVarArg = False 30 | }, pointerAddrSpace = AddrSpace 0}) (Name "foo") 31 | )), 32 | arguments = [( 33 | ConstantOperand (Int {integerBits = 32, integerValue = 9}), [] 34 | )], 35 | functionAttributes = [] 36 | }, 37 | UnName 2 := Add {nsw = False, nuw = False, operand0 = LocalReference ( 38 | IntegerType {typeBits = 32}) (UnName 1), 39 | operand1 = ConstantOperand ( 40 | Int {integerBits = 32, integerValue = 2} 41 | ) 42 | }, 43 | UnName 3 := Call { 44 | function = Right (ConstantOperand ( 45 | GlobalReference (PointerType {pointerReferent = FunctionType { 46 | resultType = IntegerType {typeBits = 32}, 47 | argumentTypes = [IntegerType {typeBits = 32}], isVarArg = False 48 | }, pointerAddrSpace = AddrSpace 0}) (Name "printi") 49 | )), 50 | arguments = [( 51 | LocalReference (IntegerType {typeBits = 32}) (UnName 2), [] 52 | )], 53 | functionAttributes = [] 54 | } 55 | ] ( 56 | Do (Ret {returnOperand = Just ( 57 | LocalReference (IntegerType {typeBits = 32}) (UnName 3) 58 | ), metadata' = []} 59 | ) 60 | )], personalityFunction = Nothing 61 | }) 62 | 63 | -- GlobalDefinition ( 64 | -- Function {linkage = External, visibility = Default, dllStorageClass = Nothing, callingConvention = C, returnAttributes = [], returnType = IntegerType {typeBits = 32}, name = Name "main", parameters = ( 65 | -- [],False), functionAttributes = [], section = Nothing, comdat = Nothing, alignment = 0, garbageCollectorName = Nothing, prefix = Nothing, basicBlocks = [BasicBlock ( 66 | -- UnName 0) [UnName 1 := Call {tailCallKind = Nothing, callingConvention = C, returnAttributes = [], function = Right ( 67 | -- ConstantOperand ( 68 | -- GlobalReference ( 69 | -- PointerType {pointerReferent = FunctionType {resultType = IntegerType {typeBits = 32}, argumentTypes = [IntegerType {typeBits = 32}], isVarArg = False}, pointerAddrSpace = AddrSpace 0}) ( 70 | -- Name "foo"))), arguments = [( 71 | -- ConstantOperand ( 72 | -- Int {integerBits = 32, integerValue = 9}),[])], functionAttributes = []},UnName 2 := Add {nsw = False, nuw = False, operand0 = LocalReference ( 73 | -- IntegerType {typeBits = 32}) ( 74 | -- UnName 1), operand1 = ConstantOperand ( 75 | -- Int {integerBits = 32, integerValue = 2})},UnName 3 := Call {tailCallKind = Nothing, callingConvention = C, returnAttributes = [], function = Right ( 76 | -- ConstantOperand ( 77 | -- GlobalReference ( 78 | -- PointerType {pointerReferent = FunctionType {resultType = IntegerType {typeBits = 32}, argumentTypes = [IntegerType {typeBits = 32}], isVarArg = False}, pointerAddrSpace = AddrSpace 0}) ( 79 | -- Name "printi"))), arguments = [( 80 | -- LocalReference ( 81 | -- IntegerType {typeBits = 32}) ( 82 | -- UnName 2),[])], functionAttributes = []}] ( 83 | -- Do ( 84 | -- Ret {returnOperand = Just ( 85 | -- LocalReference ( 86 | -- IntegerType {typeBits = 32}) ( 87 | -- UnName 3)), metadata' = []}))], personalityFunction = Nothing}) -------------------------------------------------------------------------------- /kaleidoscope/examples/llvm_example/example.ll: -------------------------------------------------------------------------------- 1 | declare i32 @putchar(i32) 2 | 3 | define void @main(){ 4 | call i32 @putchar(i32 68) 5 | call i32 @putchar(i32 101) 6 | call i32 @putchar(i32 108) 7 | call i32 @putchar(i32 108) 8 | call i32 @putchar(i32 111) 9 | call i32 @putchar(i32 44) 10 | call i32 @putchar(i32 32) 11 | call i32 @putchar(i32 87) 12 | call i32 @putchar(i32 111) 13 | call i32 @putchar(i32 114) 14 | call i32 @putchar(i32 108) 15 | call i32 @putchar(i32 100) 16 | call i32 @putchar(i32 33) 17 | call i32 @putchar(i32 10) 18 | ret void 19 | } 20 | -------------------------------------------------------------------------------- /kaleidoscope/examples/llvm_example/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("hello world\n"); 5 | return 0; 6 | } -------------------------------------------------------------------------------- /kaleidoscope/examples/llvm_example/list.ll: -------------------------------------------------------------------------------- 1 | %myStruct = type { i32, %myStruct* } 2 | 3 | define %myStruct @main() { 4 | ret %myStruct { i32 1, %myStruct* null } 5 | } 6 | 7 | define %myStruct @linked_list() { 8 | %node1 = alloca %myStruct 9 | %node2 = alloca %myStruct 10 | 11 | %node1.i32 = getelementptr %myStruct, %myStruct* %node1, i32 0, i32 0 12 | store i32 1, i32* %node1.i32 13 | 14 | %node1.next = getelementptr %myStruct, %myStruct* %node1, i32 0, i32 1 15 | store %myStruct* %node2, %myStruct** %node1.next 16 | 17 | %node2.i32 = getelementptr %myStruct, %myStruct* %node2, i32 0, i32 0 18 | store i32 2, i32* %node2.i32 19 | 20 | %node2.next = getelementptr %myStruct, %myStruct* %node2, i32 0, i32 1 21 | store %myStruct* null, %myStruct** %node2.next 22 | 23 | ret %myStruct* %node1 24 | } -------------------------------------------------------------------------------- /kaleidoscope/kaleidoscope-fing.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 3.8 2 | name: kaleidoscope-fing 3 | version: 0.1.0.0 4 | 5 | -- A short (one-line) description of the package. 6 | -- synopsis: 7 | 8 | -- A longer description of the package. 9 | -- description: 10 | 11 | -- A URL where users can report bugs. 12 | -- bug-reports: 13 | license: NONE 14 | author: Andrés Collares 15 | maintainer: andres.collares@fing.edu.uy 16 | 17 | -- A copyright notice. 18 | -- copyright: 19 | -- category: 20 | extra-source-files: CHANGELOG.md 21 | 22 | common common-options 23 | build-depends: 24 | , base ^>=4.14 25 | , llvm-hs-pure ^>=12.0 26 | 27 | ghc-options: 28 | -Wall -Wcompat -Widentities -Wincomplete-uni-patterns 29 | -Wincomplete-record-updates -Wredundant-constraints 30 | -Wnoncanonical-monad-instances -threaded -lstdc++ -dynamic 31 | 32 | if impl(ghc >=8.2) 33 | ghc-options: -fhide-source-paths 34 | 35 | if impl(ghc >=8.4) 36 | ghc-options: -Wpartial-fields 37 | 38 | if impl(ghc >=8.8) 39 | ghc-options: -Wmissing-deriving-strategies -fwrite-ide-info -hiedir=.hie 40 | 41 | if impl(ghc >=8.10) 42 | ghc-options: -Wunused-packages 43 | 44 | default-language: Haskell2010 45 | 46 | executable kaleidoscope-fing 47 | import: common-options 48 | main-is: Main.hs 49 | other-modules: 50 | Parser.Parse, Parser.Lexer, Syntax, CodeGen.JIT, CodeGen.GenModule, CodeGen.GenOperand, CodeGen.LocalVar, CodeGen.Utils.Types 51 | , StdLib.GenLibs , StdLib.BaseDefs, CLIParameters, Processor 52 | hs-source-dirs: src 53 | build-depends: 54 | , bytestring >=0.10 55 | , llvm-hs ^>=12.0 56 | , containers >=0.6 57 | , process >=1.6 58 | , directory >=1.3 59 | , mtl >=2.2 && <2.3 60 | , text ^>= 1.2 61 | , haskeline >=0.7 62 | , parsec >=3.1.0 63 | , optparse-applicative >=0.17.0.0 64 | 65 | test-suite unit-test 66 | type: exitcode-stdio-1.0 67 | main-is: Spec.hs 68 | hs-source-dirs: 69 | test 70 | , src 71 | other-modules: 72 | Parser.Parse, Parser.Lexer, Syntax, CodeGen.JIT, CodeGen.GenModule, CodeGen.GenOperand, CodeGen.LocalVar, CodeGen.Utils.Types 73 | , StdLib.GenLibs , StdLib.BaseDefs, CLIParameters, Processor 74 | ghc-options: -threaded -rtsopts -with-rtsopts=-N 75 | build-depends: 76 | base ^>=4.14 77 | , tasty 78 | , tasty-hunit 79 | , process >=1.6 80 | , directory >=1.3 81 | , bytestring >=0.10 82 | , llvm-hs ^>=12.0 83 | , llvm-hs-pure ^>=12.0 84 | , containers >=0.6 85 | , mtl >=2.2 && <2.3 86 | , text ^>= 1.2 87 | , haskeline >=0.7 88 | , parsec >=3.1.0 89 | , optparse-applicative >=0.17.0.0 90 | , filepath >=1.4.2.1 91 | default-language: Haskell2010 92 | 93 | -------------------------------------------------------------------------------- /kaleidoscope/out.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'kaleidoscope' 2 | source_filename = "" 3 | 4 | %IntList = type { i32, %IntList* } 5 | 6 | declare i32 @printi(i32) local_unnamed_addr 7 | 8 | declare %IntList* @_alloc_int_list_node() local_unnamed_addr 9 | 10 | ; Function Attrs: norecurse nounwind readnone willreturn 11 | define double @int_to_double(i32 %x_0) local_unnamed_addr #0 { 12 | %1 = sitofp i32 %x_0 to double 13 | ret double %1 14 | } 15 | 16 | ; Function Attrs: norecurse nounwind readnone willreturn 17 | define i32 @double_to_int(double %x_0) local_unnamed_addr #0 { 18 | %1 = fptosi double %x_0 to i32 19 | ret i32 %1 20 | } 21 | 22 | ; Function Attrs: nounwind readonly 23 | define i32 @length(%IntList* readonly %l_0) local_unnamed_addr #1 { 24 | %1 = icmp eq %IntList* %l_0, null 25 | br i1 %1, label %if.end_0, label %if.else_0 26 | 27 | if.else_0: ; preds = %0, %if.else_0 28 | %l_0.tr2 = phi %IntList* [ %3, %if.else_0 ], [ %l_0, %0 ] 29 | %accumulator.tr1 = phi i32 [ %4, %if.else_0 ], [ 0, %0 ] 30 | %2 = getelementptr %IntList, %IntList* %l_0.tr2, i64 0, i32 1 31 | %3 = load %IntList*, %IntList** %2, align 8 32 | %4 = add i32 %accumulator.tr1, 1 33 | %5 = icmp eq %IntList* %3, null 34 | br i1 %5, label %if.end_0, label %if.else_0 35 | 36 | if.end_0: ; preds = %if.else_0, %0 37 | %accumulator.tr.lcssa = phi i32 [ 0, %0 ], [ %4, %if.else_0 ] 38 | ret i32 %accumulator.tr.lcssa 39 | } 40 | 41 | define i1 @all(%IntList* readonly %l_0, i1 (i32)* nocapture %f_0) local_unnamed_addr { 42 | %1 = icmp eq %IntList* %l_0, null 43 | br i1 %1, label %if.end_1, label %if.else_0 44 | 45 | if.else_0: ; preds = %0, %if.then_1 46 | %l_0.tr1 = phi %IntList* [ %6, %if.then_1 ], [ %l_0, %0 ] 47 | %2 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 0 48 | %3 = load i32, i32* %2, align 4 49 | %4 = tail call i1 %f_0(i32 %3) 50 | br i1 %4, label %if.then_1, label %if.end_1 51 | 52 | if.then_1: ; preds = %if.else_0 53 | %5 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 1 54 | %6 = load %IntList*, %IntList** %5, align 8 55 | %7 = icmp eq %IntList* %6, null 56 | br i1 %7, label %if.end_1, label %if.else_0 57 | 58 | if.end_1: ; preds = %if.then_1, %if.else_0, %0 59 | %8 = phi i1 [ true, %0 ], [ %4, %if.else_0 ], [ %4, %if.then_1 ] 60 | ret i1 %8 61 | } 62 | 63 | define i1 @any(%IntList* readonly %l_0, i1 (i32)* nocapture %f_0) local_unnamed_addr { 64 | %1 = icmp eq %IntList* %l_0, null 65 | br i1 %1, label %if.end_1, label %if.else_0 66 | 67 | if.else_0: ; preds = %0, %if.else_1 68 | %l_0.tr1 = phi %IntList* [ %6, %if.else_1 ], [ %l_0, %0 ] 69 | %2 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 0 70 | %3 = load i32, i32* %2, align 4 71 | %4 = tail call i1 %f_0(i32 %3) 72 | br i1 %4, label %if.end_1, label %if.else_1 73 | 74 | if.else_1: ; preds = %if.else_0 75 | %5 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 1 76 | %6 = load %IntList*, %IntList** %5, align 8 77 | %7 = icmp eq %IntList* %6, null 78 | br i1 %7, label %if.end_1, label %if.else_0 79 | 80 | if.end_1: ; preds = %if.else_1, %if.else_0, %0 81 | %8 = phi i1 [ false, %0 ], [ %4, %if.else_0 ], [ %4, %if.else_1 ] 82 | ret i1 %8 83 | } 84 | 85 | define %IntList* @map_int(%IntList* readonly %l_0, i32 (i32)* nocapture %f_0) local_unnamed_addr { 86 | %1 = icmp eq %IntList* %l_0, null 87 | br i1 %1, label %if.end_0, label %if.else_0 88 | 89 | if.else_0: ; preds = %0 90 | %2 = getelementptr %IntList, %IntList* %l_0, i64 0, i32 0 91 | %3 = load i32, i32* %2, align 4 92 | %4 = tail call i32 %f_0(i32 %3) 93 | %5 = getelementptr %IntList, %IntList* %l_0, i64 0, i32 1 94 | %6 = load %IntList*, %IntList** %5, align 8 95 | %7 = tail call %IntList* @map_int(%IntList* %6, i32 (i32)* %f_0) 96 | %8 = tail call %IntList* @_alloc_int_list_node() 97 | %9 = getelementptr %IntList, %IntList* %8, i64 0, i32 0 98 | store i32 %4, i32* %9, align 4 99 | %10 = getelementptr %IntList, %IntList* %8, i64 0, i32 1 100 | store %IntList* %7, %IntList** %10, align 8 101 | ret %IntList* %8 102 | 103 | if.end_0: ; preds = %0 104 | ret %IntList* null 105 | } 106 | 107 | define %IntList* @filter_int(%IntList* readonly %l_0, i1 (i32)* %f_0) local_unnamed_addr { 108 | %1 = icmp eq %IntList* %l_0, null 109 | br i1 %1, label %if.end_1, label %if.else_0 110 | 111 | if.else_0: ; preds = %0, %if.else_1 112 | %l_0.tr2 = phi %IntList* [ %14, %if.else_1 ], [ %l_0, %0 ] 113 | %2 = getelementptr %IntList, %IntList* %l_0.tr2, i64 0, i32 0 114 | %3 = load i32, i32* %2, align 4 115 | %4 = tail call i1 %f_0(i32 %3) 116 | br i1 %4, label %if.then_1, label %if.else_1 117 | 118 | if.then_1: ; preds = %if.else_0 119 | %5 = getelementptr %IntList, %IntList* %l_0.tr2, i64 0, i32 0 120 | %6 = load i32, i32* %5, align 4 121 | %7 = getelementptr %IntList, %IntList* %l_0.tr2, i64 0, i32 1 122 | %8 = load %IntList*, %IntList** %7, align 8 123 | %9 = tail call %IntList* @filter_int(%IntList* %8, i1 (i32)* %f_0) 124 | %10 = tail call %IntList* @_alloc_int_list_node() 125 | %11 = getelementptr %IntList, %IntList* %10, i64 0, i32 0 126 | store i32 %6, i32* %11, align 4 127 | %12 = getelementptr %IntList, %IntList* %10, i64 0, i32 1 128 | store %IntList* %9, %IntList** %12, align 8 129 | ret %IntList* %10 130 | 131 | if.else_1: ; preds = %if.else_0 132 | %13 = getelementptr %IntList, %IntList* %l_0.tr2, i64 0, i32 1 133 | %14 = load %IntList*, %IntList** %13, align 8 134 | %15 = icmp eq %IntList* %14, null 135 | br i1 %15, label %if.end_1, label %if.else_0 136 | 137 | if.end_1: ; preds = %if.else_1, %0 138 | ret %IntList* null 139 | } 140 | 141 | ; Function Attrs: nounwind readonly 142 | define i32 @nth_int(%IntList* nocapture readonly %l_0, i32 %n_0) local_unnamed_addr #1 { 143 | %1 = icmp eq i32 %n_0, 0 144 | br i1 %1, label %if.if_exit_0, label %if.else_0 145 | 146 | if.else_0: ; preds = %0, %if.else_0 147 | %n_0.tr2 = phi i32 [ %4, %if.else_0 ], [ %n_0, %0 ] 148 | %l_0.tr1 = phi %IntList* [ %3, %if.else_0 ], [ %l_0, %0 ] 149 | %2 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 1 150 | %3 = load %IntList*, %IntList** %2, align 8 151 | %4 = add i32 %n_0.tr2, -1 152 | %5 = icmp eq i32 %4, 0 153 | br i1 %5, label %if.if_exit_0, label %if.else_0 154 | 155 | if.if_exit_0: ; preds = %if.else_0, %0 156 | %l_0.tr.lcssa = phi %IntList* [ %l_0, %0 ], [ %3, %if.else_0 ] 157 | %6 = getelementptr %IntList, %IntList* %l_0.tr.lcssa, i64 0, i32 0 158 | %7 = load i32, i32* %6, align 4 159 | ret i32 %7 160 | } 161 | 162 | define %IntList* @reverse_acc_int(%IntList* readonly %l_0, %IntList* %acc_0) local_unnamed_addr { 163 | %1 = icmp eq %IntList* %l_0, null 164 | br i1 %1, label %if.end_0, label %if.else_0 165 | 166 | if.else_0: ; preds = %0, %if.else_0 167 | %acc_0.tr2 = phi %IntList* [ %6, %if.else_0 ], [ %acc_0, %0 ] 168 | %l_0.tr1 = phi %IntList* [ %3, %if.else_0 ], [ %l_0, %0 ] 169 | %2 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 1 170 | %3 = load %IntList*, %IntList** %2, align 8 171 | %4 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 0 172 | %5 = load i32, i32* %4, align 4 173 | %6 = tail call %IntList* @_alloc_int_list_node() 174 | %7 = getelementptr %IntList, %IntList* %6, i64 0, i32 0 175 | store i32 %5, i32* %7, align 4 176 | %8 = getelementptr %IntList, %IntList* %6, i64 0, i32 1 177 | store %IntList* %acc_0.tr2, %IntList** %8, align 8 178 | %9 = icmp eq %IntList* %3, null 179 | br i1 %9, label %if.end_0, label %if.else_0 180 | 181 | if.end_0: ; preds = %if.else_0, %0 182 | %acc_0.tr.lcssa = phi %IntList* [ %acc_0, %0 ], [ %6, %if.else_0 ] 183 | ret %IntList* %acc_0.tr.lcssa 184 | } 185 | 186 | define %IntList* @reverse_int(%IntList* readonly %l_0) local_unnamed_addr { 187 | %1 = tail call %IntList* @reverse_acc_int(%IntList* %l_0, %IntList* null) 188 | ret %IntList* %1 189 | } 190 | 191 | define i32 @foldl_int(%IntList* readonly %l_0, i32 %acc_0, i32 (i32, i32)* nocapture %f_0) local_unnamed_addr { 192 | %1 = icmp eq %IntList* %l_0, null 193 | br i1 %1, label %if.end_0, label %if.else_0 194 | 195 | if.else_0: ; preds = %0, %if.else_0 196 | %acc_0.tr2 = phi i32 [ %6, %if.else_0 ], [ %acc_0, %0 ] 197 | %l_0.tr1 = phi %IntList* [ %3, %if.else_0 ], [ %l_0, %0 ] 198 | %2 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 1 199 | %3 = load %IntList*, %IntList** %2, align 8 200 | %4 = getelementptr %IntList, %IntList* %l_0.tr1, i64 0, i32 0 201 | %5 = load i32, i32* %4, align 4 202 | %6 = tail call i32 %f_0(i32 %acc_0.tr2, i32 %5) 203 | %7 = icmp eq %IntList* %3, null 204 | br i1 %7, label %if.end_0, label %if.else_0 205 | 206 | if.end_0: ; preds = %if.else_0, %0 207 | %acc_0.tr.lcssa = phi i32 [ %acc_0, %0 ], [ %6, %if.else_0 ] 208 | ret i32 %acc_0.tr.lcssa 209 | } 210 | 211 | define i32 @foldr_int(%IntList* readonly %l_0, i32 %acc_0, i32 (i32, i32)* nocapture %f_0) local_unnamed_addr { 212 | %1 = icmp eq %IntList* %l_0, null 213 | br i1 %1, label %if.end_0, label %if.else_0 214 | 215 | if.else_0: ; preds = %0 216 | %2 = getelementptr %IntList, %IntList* %l_0, i64 0, i32 0 217 | %3 = load i32, i32* %2, align 4 218 | %4 = getelementptr %IntList, %IntList* %l_0, i64 0, i32 1 219 | %5 = load %IntList*, %IntList** %4, align 8 220 | %6 = tail call i32 @foldr_int(%IntList* %5, i32 %acc_0, i32 (i32, i32)* %f_0) 221 | %7 = tail call i32 %f_0(i32 %3, i32 %6) 222 | ret i32 %7 223 | 224 | if.end_0: ; preds = %0 225 | ret i32 %acc_0 226 | } 227 | 228 | ; Function Attrs: norecurse nounwind readnone willreturn 229 | define i32 @max_tuple_int({ i32, i32 } %x_0) local_unnamed_addr #0 { 230 | if.end_0: 231 | %x_0.elt = extractvalue { i32, i32 } %x_0, 0 232 | %x_0.elt5 = extractvalue { i32, i32 } %x_0, 1 233 | %0 = icmp ugt i32 %x_0.elt, %x_0.elt5 234 | %spec.select = select i1 %0, i32 %x_0.elt, i32 %x_0.elt5 235 | ret i32 %spec.select 236 | } 237 | 238 | ; Function Attrs: nounwind readnone 239 | define i32 @fib(i32 %x_0) local_unnamed_addr #2 { 240 | %1 = icmp ult i32 %x_0, 3 241 | br i1 %1, label %if.end_0, label %if.else_0 242 | 243 | if.else_0: ; preds = %0, %if.else_0 244 | %x_0.tr2 = phi i32 [ %4, %if.else_0 ], [ %x_0, %0 ] 245 | %accumulator.tr1 = phi i32 [ %5, %if.else_0 ], [ 0, %0 ] 246 | %2 = add i32 %x_0.tr2, -1 247 | %3 = tail call i32 @fib(i32 %2) 248 | %4 = add i32 %x_0.tr2, -2 249 | %5 = add i32 %3, %accumulator.tr1 250 | %6 = icmp ult i32 %4, 3 251 | br i1 %6, label %if.end_0.loopexit, label %if.else_0 252 | 253 | if.end_0.loopexit: ; preds = %if.else_0 254 | %phi.bo = add i32 %5, 1 255 | br label %if.end_0 256 | 257 | if.end_0: ; preds = %if.end_0.loopexit, %0 258 | %accumulator.tr.lcssa = phi i32 [ 1, %0 ], [ %phi.bo, %if.end_0.loopexit ] 259 | ret i32 %accumulator.tr.lcssa 260 | } 261 | 262 | define i32 @main() local_unnamed_addr { 263 | %1 = tail call i32 @fib(i32 6) 264 | %2 = tail call i32 @printi(i32 %1) 265 | ret i32 %2 266 | } 267 | 268 | attributes #0 = { norecurse nounwind readnone willreturn } 269 | attributes #1 = { nounwind readonly } 270 | attributes #2 = { nounwind readnone } 271 | -------------------------------------------------------------------------------- /kaleidoscope/src/CLIParameters.hs: -------------------------------------------------------------------------------- 1 | module CLIParameters where 2 | 3 | import Options.Applicative 4 | 5 | data CLIParameters = CLIParameters 6 | { optimizationLevel :: Word, 7 | inputFile :: String, 8 | emitLLVM :: Bool, 9 | emitAST :: Bool, 10 | emitLlvmDefs :: Bool, 11 | failOnErrors :: Bool, 12 | compile :: Bool 13 | } 14 | 15 | parserParameters :: Parser CLIParameters 16 | parserParameters = 17 | CLIParameters 18 | <$> option 19 | auto 20 | ( long "opt-level" 21 | <> short 'o' 22 | <> metavar "OPT" 23 | <> value 3 24 | <> help "Optimization level 0-3" 25 | ) 26 | <*> strOption 27 | ( long "file" 28 | <> short 'f' 29 | <> metavar "FILE" 30 | <> value [] 31 | <> help "File to read from" 32 | ) 33 | <*> flag 34 | False 35 | True 36 | ( long "llvm" 37 | <> short 'l' 38 | <> help "Show LLVM IR output" 39 | ) 40 | <*> flag 41 | False 42 | True 43 | ( long "ast" 44 | <> short 'a' 45 | <> help "Show AST representation" 46 | ) 47 | <*> flag 48 | False 49 | True 50 | ( long "defs" 51 | <> short 'd' 52 | <> help "Show LLVM Module definitions" 53 | ) 54 | <*> flag 55 | False 56 | True 57 | ( long "fail-on-errors" 58 | <> short 'e' 59 | <> help "Fail on errors" 60 | ) 61 | <*> flag 62 | False 63 | True 64 | ( long "compile" 65 | <> short 'c' 66 | <> help "Compile to native code" 67 | ) 68 | -------------------------------------------------------------------------------- /kaleidoscope/src/CodeGen/GenModule.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DerivingStrategies #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE RecursiveDo #-} 4 | 5 | module CodeGen.GenModule where 6 | 7 | import CodeGen.GenOperand (genOperand) 8 | import CodeGen.LocalVar 9 | ( LocalVar, 10 | localVarsFallback, 11 | ) 12 | import CodeGen.Utils.Types (operandType, syntaxTypeToASTType) 13 | import Data.Bifunctor (first) 14 | import Data.Map.Strict (fromList) 15 | import LLVM.AST as AST hiding (function) 16 | import LLVM.AST.Attribute (ParameterAttribute) 17 | import qualified LLVM.AST.Constant as C 18 | import LLVM.AST.Global (Global (name), basicBlocks, parameters, returnType) 19 | import LLVM.AST.Type (i32, i8, ptr) 20 | import qualified LLVM.AST.Type as ASTType 21 | import LLVM.IRBuilder (ParameterName (ParameterName), call, extractValue, globalStringPtr, int32, load, select) 22 | import LLVM.IRBuilder.Instruction (ret) 23 | import LLVM.IRBuilder.Internal.SnocList (SnocList (SnocList)) 24 | import LLVM.IRBuilder.Module (ModuleBuilder, ModuleBuilderState (ModuleBuilderState, builderDefs, builderTypeDefs), emitDefn, execModuleBuilder, extern, function) 25 | import LLVM.IRBuilder.Monad (IRBuilderT) 26 | import qualified Syntax as S 27 | 28 | -- Generates the Module from the previous module and the new expressions 29 | -- Has to optimize the module 30 | -- Has to execute the module 31 | -- Has to update the module state 32 | genModule :: [Definition] -> [S.TopLevel] -> [Definition] 33 | genModule oldDefs expressions = buildModuleDefinitions (removeMain oldDefs) newModlState 34 | where 35 | removeMain (def : defs) = case def of 36 | GlobalDefinition AST.Function {name = Name "main"} -> defs 37 | _ -> def : removeMain defs 38 | removeMain [] = [] 39 | -- use old state and new expressions to generate the new state 40 | newModlState = mapM genTopLevel expressions 41 | 42 | buildModuleDefinitions :: [Definition] -> ModuleBuilder a -> [Definition] 43 | buildModuleDefinitions prevDefs = execModuleBuilder oldModl 44 | where 45 | oldModl = ModuleBuilderState {builderDefs = SnocList (reverse prevDefs), builderTypeDefs = typeDefsMap} 46 | -- TODO: Do we even have type definitions? 47 | typeDefsMap = fromList $ map (\(TypeDefinition definitionName (Just t)) -> (definitionName, t)) typeDefs 48 | typeDefs = filter isTypeDef prevDefs 49 | isTypeDef (TypeDefinition _ _) = True 50 | isTypeDef _ = False 51 | 52 | -- Generates functions, externs, definitions and a main function otherwise 53 | -- The result is a ModuleBuilder monad 54 | genTopLevel :: S.TopLevel -> ModuleBuilder AST.Operand 55 | -- Extern definition 56 | genTopLevel (S.Declaration (S.Extern externName externArgs retType)) = do 57 | extern externName (map (syntaxTypeToASTType . fst) externArgs) (syntaxTypeToASTType retType) 58 | 59 | -- Function definition 60 | genTopLevel (S.Declaration (S.Function fnName fnArgs retType body)) = do 61 | let astRetType = syntaxTypeToASTType retType 62 | -- Define the function signature first 63 | emitDefn $ 64 | GlobalDefinition 65 | functionDefaults 66 | { name = fnName, 67 | parameters = (map (\(t, ParameterName n) -> Parameter (syntaxTypeToASTType t) (Name n) []) fnArgs, False), 68 | returnType = astRetType, 69 | basicBlocks = [] 70 | } 71 | -- Generate the function body 72 | function 73 | fnName 74 | (first syntaxTypeToASTType <$> fnArgs) 75 | astRetType 76 | (genLevel body . localVarsFallback) 77 | 78 | -- Main expression 79 | genTopLevel (S.Expr expression) = do 80 | function "main" [] i32 (\_ -> genMain expression []) 81 | 82 | genLevel :: S.Expr -> [LocalVar] -> IRBuilderT ModuleBuilder () 83 | genLevel e localVars = do 84 | operand <- genOperand e localVars 85 | ret operand 86 | 87 | genMain :: S.Expr -> [LocalVar] -> IRBuilderT ModuleBuilder () 88 | genMain e localVars = do 89 | operand <- genOperand e localVars 90 | genPrint operand 91 | ret $ int32 0 92 | 93 | genPrint :: AST.Operand -> IRBuilderT ModuleBuilder () 94 | genPrint operand = mdo 95 | let fmtStr = getFmtString $ operandType operand 96 | fmtStrGlobal <- globalStringPtr (fmtStr ++ "\n") "fmtStr" 97 | 98 | printArgs <- operandToPrintfArg operand 99 | _ <- 100 | call 101 | (ConstantOperand (C.GlobalReference (ASTType.ptr (ASTType.FunctionType i32 [ptr i8] True)) (mkName "printf"))) 102 | ((ConstantOperand fmtStrGlobal, []) : printArgs) 103 | return () 104 | 105 | getFmtString :: AST.Type -> String 106 | getFmtString opType = 107 | case opType of 108 | ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [t1, t2]}} -> 109 | if isList t2 110 | then "[" ++ getFmtStringForList opType ++ "]" 111 | else "(" ++ getFmtString t1 ++ ", " ++ getFmtString t2 ++ ")" 112 | -- Empty list 113 | ASTType.PointerType {ASTType.pointerReferent = ASTType.PointerType {ASTType.pointerReferent = ASTType.VoidType}} -> "[%s]" 114 | _ -> getFmtStringForAtom opType 115 | 116 | getFmtStringForList :: ASTType.Type -> String 117 | -- Last node of a list 118 | getFmtStringForList 119 | ASTType.PointerType 120 | { ASTType.pointerReferent = 121 | ASTType.StructureType 122 | { ASTType.elementTypes = 123 | [ t1, 124 | ASTType.PointerType {ASTType.pointerReferent = ASTType.PointerType {ASTType.pointerReferent = ASTType.VoidType}} 125 | ] 126 | } 127 | } = 128 | if isList t1 129 | then getFmtString t1 130 | else case t1 of 131 | ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [_, _]}} -> 132 | getFmtString t1 133 | _ -> getFmtStringForList t1 134 | -- Tuple or node of a list 135 | getFmtStringForList ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [t1, t2]}} = 136 | if isList t1 137 | then getFmtString t1 ++ ", " ++ getFmtStringForList t2 138 | else case t1 of 139 | ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [_, _]}} -> 140 | getFmtString t1 ++ ", " ++ getFmtStringForList t2 141 | _ -> getFmtStringForList t1 ++ ", " ++ getFmtStringForList t2 142 | getFmtStringForList opType = getFmtStringForAtom opType 143 | 144 | getFmtStringForAtom :: ASTType.Type -> String 145 | getFmtStringForAtom ASTType.IntegerType {ASTType.typeBits = 32} = "%d" 146 | getFmtStringForAtom ASTType.FloatingPointType {ASTType.floatingPointType = ASTType.DoubleFP} = "%f" 147 | -- HACK: just "%s" results in an error ¯\_(ツ)_/¯ 148 | getFmtStringForAtom ASTType.IntegerType {ASTType.typeBits = 1} = "%se" 149 | getFmtStringForAtom opType = error "Unsupported type for printf format: " ++ show opType 150 | 151 | isList :: ASTType.Type -> Bool 152 | isList ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [_, next]}} = 153 | isList next 154 | isList ASTType.PointerType {ASTType.pointerReferent = ASTType.PointerType {ASTType.pointerReferent = ASTType.VoidType}} = 155 | True 156 | isList _ = False 157 | 158 | operandToPrintfArg :: AST.Operand -> IRBuilderT ModuleBuilder [(AST.Operand, [ParameterAttribute])] 159 | operandToPrintfArg operand = case operandType operand of 160 | ASTType.IntegerType {ASTType.typeBits = 32} -> return [(operand, [])] 161 | ASTType.FloatingPointType {ASTType.floatingPointType = ASTType.DoubleFP} -> return [(operand, [])] 162 | ASTType.IntegerType {ASTType.typeBits = 1} -> do 163 | -- Convert boolean to string pointer directly using select 164 | ts <- globalStringPtr "tru" "t_str" 165 | fs <- globalStringPtr "fals" "f_str" 166 | 167 | strPtr <- select operand (ConstantOperand ts) (ConstantOperand fs) 168 | return [(strPtr, [])] 169 | -- Last Node of a list 170 | ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [_, ASTType.PointerType {ASTType.pointerReferent = ASTType.PointerType {ASTType.pointerReferent = ASTType.VoidType}}]}} -> do 171 | tuple <- load operand 0 172 | val1 <- extractValue tuple [0] 173 | operandToPrintfArg val1 174 | -- Tuple and list Node 175 | ASTType.PointerType {ASTType.pointerReferent = ASTType.StructureType {ASTType.elementTypes = [_, _]}} -> do 176 | tuple <- load operand 0 177 | val1 <- extractValue tuple [0] 178 | val2 <- extractValue tuple [1] 179 | args1 <- operandToPrintfArg val1 180 | args2 <- operandToPrintfArg val2 181 | return $ args1 ++ args2 182 | -- Empty list 183 | ASTType.PointerType {ASTType.pointerReferent = ASTType.PointerType {ASTType.pointerReferent = ASTType.VoidType}} -> do 184 | -- HACK: printf breaks if I don't provide sufficient arguments 185 | emptyListStr <- globalStringPtr " " "empty_list_str" 186 | return [(ConstantOperand emptyListStr, [])] 187 | _ -> error $ "Unsupported type for printf argument: " ++ show (operandType operand) -------------------------------------------------------------------------------- /kaleidoscope/src/CodeGen/GenOperand.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DerivingStrategies #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE RecursiveDo #-} 4 | 5 | module CodeGen.GenOperand where 6 | 7 | import CodeGen.LocalVar 8 | ( LocalVar, 9 | getFunctionOperand, 10 | getLocalVarByName, 11 | ) 12 | import CodeGen.Utils.Types (operandType) 13 | import Control.Monad.RWS (gets) 14 | import qualified Data.Map.Strict as M 15 | import Data.Word (Word32) 16 | import LLVM.AST as AST 17 | ( Definition (GlobalDefinition), 18 | Global (Function), 19 | Instruction (Store), 20 | Name (Name), 21 | Operand (ConstantOperand), 22 | Type (..), 23 | ) 24 | import qualified LLVM.AST.Constant as C 25 | import qualified LLVM.AST.Float as F 26 | import LLVM.AST.FloatingPointPredicate (FloatingPointPredicate (UEQ, UGE, UGT, ULE, ULT, UNE)) 27 | import qualified LLVM.AST.Global as AST.Global 28 | import qualified LLVM.AST.Global as G 29 | import qualified LLVM.AST.IntegerPredicate as IP 30 | import qualified LLVM.AST.Type as ASTType 31 | import LLVM.IRBuilder (ModuleBuilder, MonadIRBuilder, builderDefs, emitInstrVoid, liftModuleState) 32 | import LLVM.IRBuilder.Constant (bit, double, int32) 33 | import LLVM.IRBuilder.Instruction 34 | import LLVM.IRBuilder.Internal.SnocList (SnocList (SnocList)) 35 | import LLVM.IRBuilder.Monad (IRBuilderT, block, named) 36 | import qualified Syntax as S 37 | import qualified LLVM.AST.Constant as Constant 38 | 39 | -- Generates the Operands that genTopLevel needs. 40 | genOperand :: S.Expr -> [LocalVar] -> IRBuilderT ModuleBuilder AST.Operand 41 | 42 | -- Constants 43 | genOperand (S.Float n) _ = return $ double n 44 | genOperand (S.Int n) _ = return $ int32 n 45 | genOperand (S.Bool b) _ = return $ bit (if b then 1 else 0) 46 | 47 | -- Variables 48 | genOperand (S.Var (Name nameString)) localVars = do 49 | -- if localVars has it then it's a local reference otherwise mark it as a global reference 50 | -- local variable names end in "_number" so we need to take that into consideration 51 | -- also local variable names can have "_" 52 | case getLocalVarByName nameString localVars of 53 | Just (_, localVar) -> return localVar 54 | Nothing -> do 55 | currentDefs <- liftModuleState $ gets builderDefs 56 | let maybeDef = getFunctionFromDefs currentDefs (Name nameString) 57 | case maybeDef of 58 | Just (GlobalDefinition AST.Function {G.returnType = retT, G.parameters = params}) -> return $ getFunctionOperand (Name nameString) retT params 59 | Just def -> error $ "Constant " <> show nameString <> " not found as global variable." <> show def 60 | Nothing -> error $ "Constant " <> show nameString <> " not found." <> show localVars 61 | 62 | -- Call 63 | genOperand (S.Call (Name fnName) functionArgs) localVars = do 64 | largs <- mapM (`genOperand` localVars) functionArgs 65 | currentDefs <- liftModuleState $ gets builderDefs 66 | let maybeDef = getFunctionFromDefs currentDefs (Name fnName) 67 | case maybeDef of 68 | Just (GlobalDefinition AST.Function {G.returnType = retT, G.parameters = params}) -> 69 | call (getFunctionOperand (Name fnName) retT params) (map (\x -> (x, [])) largs) 70 | Just _ -> error $ "Function " <> show fnName <> " not found." 71 | Nothing -> do 72 | let localVar = getLocalVarByName fnName localVars 73 | case localVar of 74 | -- This only happens if we're in a high level function where there's a function as an attribute. 75 | Just (_, localFunctionVar) -> call localFunctionVar (map (\x -> (x, [])) largs) 76 | Nothing -> error $ "Function " <> show fnName <> " not found." 77 | 78 | -- Unary Operands (Prefix Operands) 79 | genOperand (S.UnaryOp oper a) localVars = do 80 | op <- genOperand a localVars 81 | case M.lookup oper unops of 82 | Just f -> f op 83 | Nothing -> error $ "Unary operation not defined: " <> show oper 84 | where 85 | unops :: M.Map Name (AST.Operand -> IRBuilderT ModuleBuilder AST.Operand) 86 | unops = 87 | M.fromList 88 | [ ( "-", 89 | \x -> case operandType x of 90 | (IntegerType _) -> sub (int32 0) x 91 | (FloatingPointType _) -> fsub (ConstantOperand (C.Float (F.Double 0))) x 92 | _ -> error $ "Invalid type for operand: " ++ show (operandType x) 93 | ), 94 | ("!", not'), 95 | ( "fst", 96 | \tuplePtr -> do 97 | tuple <- load tuplePtr 0 98 | extractValue tuple [0] 99 | ), 100 | ( "snd", 101 | \tuplePtr -> do 102 | tuple <- load tuplePtr 0 103 | extractValue tuple [1] 104 | ), 105 | ( "tail", 106 | \x -> do 107 | i32_slot <- gep x [int32 0, int32 1] 108 | load i32_slot 0 109 | ), 110 | ( "head", 111 | \x -> do 112 | i32_slot <- gep x [int32 0, int32 0] 113 | load i32_slot 0 114 | ) 115 | ] 116 | where 117 | not' :: AST.Operand -> IRBuilderT ModuleBuilder AST.Operand 118 | not' x = icmp IP.EQ x (bit 0) 119 | -- Binary Operands (Infix Operands) 120 | genOperand (S.BinOp ":" x xs) localVars = do 121 | xOper <- genOperand x localVars 122 | xsOper <- genOperand xs localVars 123 | 124 | newListStruct <- alloca (ASTType.StructureType False [operandType xOper, operandType xsOper]) Nothing 0 125 | 126 | xPtr <- gep newListStruct [int32 0, int32 0] 127 | storeVolatile xPtr 0 xOper 128 | xsPtr <- gep newListStruct [int32 0, int32 1] 129 | storeVolatile xsPtr 0 xsOper 130 | 131 | return newListStruct 132 | genOperand (S.BinOp oper a b) localVars = do 133 | opA <- genOperand a localVars 134 | opB <- genOperand b localVars 135 | case M.lookup oper $ binops opA opB of 136 | Just f -> f opA opB 137 | Nothing -> error $ "Binary operation not defined: " <> show oper 138 | where 139 | binops :: AST.Operand -> AST.Operand -> M.Map Name (AST.Operand -> AST.Operand -> IRBuilderT ModuleBuilder AST.Operand) 140 | binops firstOp secondOp = 141 | M.fromList 142 | [ ("+", eitherType add fadd), 143 | ("-", eitherType sub fsub), 144 | ("*", eitherType mul fmul), 145 | ("/", eitherType udiv fdiv), 146 | ("%", eitherType urem frem), 147 | ("<", eitherType (icmp IP.ULT) (fcmp ULT)), 148 | ("<=", eitherType (icmp IP.ULE) (fcmp ULE)), 149 | (">", eitherType (icmp IP.UGT) (fcmp UGT)), 150 | (">=", eitherType (icmp IP.UGE) (fcmp UGE)), 151 | ("==", eitherType (icmp IP.EQ) (fcmp UEQ)), 152 | ("!=", eitherType (icmp IP.NE) (fcmp UNE)), 153 | ("^^", LLVM.IRBuilder.Instruction.xor), 154 | ("&&", LLVM.IRBuilder.Instruction.and), 155 | ("||", LLVM.IRBuilder.Instruction.or) 156 | ] 157 | where 158 | eitherType = typedOperandInstruction firstOp secondOp 159 | -- If 160 | -- NOTE: Extra if_exit and else_exit labels are necessary 161 | genOperand (S.If cond thenExpr elseExpr) localVars = mdo 162 | computedCond <- genOperand cond localVars 163 | condBr computedCond ifThen ifElse 164 | ifThen <- block `named` "if.then" 165 | computedThen <- genOperand thenExpr localVars 166 | br ifExit 167 | ifElse <- block `named` "if.else" 168 | computedElse <- genOperand elseExpr localVars 169 | br elseExit 170 | ifExit <- block `named` "if.if_exit" 171 | br blockEnd 172 | elseExit <- block `named` "if.else_exit" 173 | br blockEnd 174 | blockEnd <- block `named` "if.end" 175 | phi [(computedThen, ifExit), (computedElse, elseExit)] 176 | -- Let in 177 | genOperand (S.Let (Name varName) variableValue body) localVars = do 178 | var <- genOperand variableValue localVars 179 | genOperand body ((Just varName, var) : localVars) 180 | -- Tuple 181 | genOperand (S.TupleI a b) localVars = do 182 | opA <- genOperand a localVars 183 | opB <- genOperand b localVars 184 | 185 | tupleStruct <- alloca (ASTType.StructureType False [operandType opA, operandType opB]) Nothing 0 186 | 187 | opAPtr <- gep tupleStruct [int32 0, int32 0] 188 | storeVolatile opAPtr 0 opA 189 | opBPtr <- gep tupleStruct [int32 0, int32 1] 190 | storeVolatile opBPtr 0 opB 191 | 192 | return tupleStruct 193 | -- Lists 194 | genOperand (S.List []) _ = return $ ConstantOperand $ Constant.Null (ASTType.ptr ASTType.VoidType) 195 | genOperand (S.List (x : xs)) localVars = do 196 | firstElem <- genOperand x localVars 197 | rest <- genOperand (S.List xs) localVars 198 | 199 | listStruct <- alloca (ASTType.StructureType False [operandType firstElem, operandType rest]) Nothing 0 200 | 201 | firstElemPtr <- gep listStruct [int32 0, int32 0] 202 | storeVolatile firstElemPtr 0 firstElem 203 | restPtr <- gep listStruct [int32 0, int32 1] 204 | storeVolatile restPtr 0 rest 205 | 206 | return listStruct 207 | genOperand x _ = error $ "This shouldn't have matched here: " <> show x 208 | 209 | storeVolatile :: MonadIRBuilder m => Operand -> Word32 -> Operand -> m () 210 | storeVolatile addr align val = emitInstrVoid $ Store True addr val Nothing align [] 211 | 212 | type BinOpInstruction = (AST.Operand -> AST.Operand -> IRBuilderT ModuleBuilder AST.Operand) 213 | 214 | typedOperandInstruction :: AST.Operand -> AST.Operand -> BinOpInstruction -> BinOpInstruction -> BinOpInstruction 215 | typedOperandInstruction a b wholeInstr floatingInstr = do 216 | let aType = operandType a 217 | let bType = operandType b 218 | case aType of 219 | (IntegerType _) -> case bType of 220 | (IntegerType _) -> wholeInstr 221 | (FloatingPointType _) -> \x y -> do 222 | x' <- sitofp x ASTType.double 223 | floatingInstr x' y 224 | _ -> error $ "Invalid types for operand: " ++ show aType ++ " and " ++ show bType 225 | (FloatingPointType _) -> case bType of 226 | (IntegerType 1) -> \x y -> do 227 | x' <- fptosi x ASTType.double 228 | floatingInstr x' y 229 | (IntegerType _) -> \x y -> do 230 | y' <- sitofp y ASTType.double 231 | floatingInstr x y' 232 | (FloatingPointType _) -> floatingInstr 233 | _ -> error $ "Invalid types for operand: " ++ show aType ++ " and " ++ show bType 234 | (ASTType.PointerType _ _) -> case bType of 235 | (ASTType.PointerType _ _) -> wholeInstr 236 | _ -> error "Pointers can only be compared to other pointers" 237 | _ -> error $ "Invalid types for operand: " ++ show aType ++ " and " ++ show bType 238 | 239 | getFunctionFromDefs :: SnocList Definition -> Name -> Maybe Definition 240 | getFunctionFromDefs defs functionName = find (`matchNameGlobal` functionName) defs Nothing 241 | where 242 | find :: (a -> Bool) -> SnocList a -> Maybe a -> Maybe a 243 | find p (SnocList (x : xs)) res 244 | | p x = Just x 245 | | otherwise = find p (SnocList xs) res 246 | find _ (SnocList []) res = res 247 | 248 | matchNameGlobal :: Definition -> Name -> Bool 249 | matchNameGlobal (GlobalDefinition AST.Function {AST.Global.name = n}) nameToMatch = n == nameToMatch 250 | matchNameGlobal _ _ = False -------------------------------------------------------------------------------- /kaleidoscope/src/CodeGen/JIT.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module CodeGen.JIT where 4 | 5 | import CLIParameters (CLIParameters (CLIParameters, compile, emitLLVM, inputFile, optimizationLevel)) 6 | import qualified Data.ByteString as BS 7 | import Foreign.C.Types (CInt (..)) 8 | import Foreign.Ptr (FunPtr, castFunPtr) 9 | import qualified LLVM.AST as AST 10 | import LLVM.Context (Context, withContext) 11 | import qualified LLVM.ExecutionEngine as EE 12 | import LLVM.Module as Mod 13 | ( moduleAST, 14 | moduleLLVMAssembly, 15 | withModuleFromAST, 16 | ) 17 | import LLVM.PassManager 18 | ( PassSetSpec (optLevel), 19 | defaultCuratedPassSetSpec, 20 | runPassManager, 21 | withPassManager, 22 | ) 23 | import System.Process (system) 24 | 25 | foreign import ccall "dynamic" haskFunInt :: FunPtr CInt -> CInt 26 | 27 | runInteger :: FunPtr a -> CInt 28 | runInteger fn = haskFunInt (castFunPtr fn :: FunPtr CInt) 29 | 30 | jit :: Context -> Word -> (EE.MCJIT -> IO a) -> IO a 31 | jit c oLevel = EE.withMCJIT c optlevel model ptrelim fastins 32 | where 33 | optlevel = Just oLevel -- optimization level 34 | model = Nothing -- code model ( Default ) 35 | ptrelim = Nothing -- frame pointer elimination 36 | fastins = Nothing -- fast instruction selection 37 | 38 | optimizeModule :: AST.Module -> CLIParameters -> IO AST.Module 39 | optimizeModule astModule CLIParameters {optimizationLevel = level, emitLLVM = emit, compile = compileFile, inputFile = file} = do 40 | withContext $ \context -> 41 | jit context level $ \_ -> 42 | withModuleFromAST context astModule $ \m -> 43 | withPassManager (defaultCuratedPassSetSpec {optLevel = Just level}) $ \pm -> do 44 | -- Optimization Pass 45 | _ <- runPassManager pm m 46 | optmod <- moduleAST m 47 | if emit && not compileFile 48 | then do 49 | modByteString <- moduleLLVMAssembly m 50 | -- Print the optimized module as LLVM assembly to stdout 51 | putStrLn "Optimized LLVM assembly:" 52 | putStrLn $ modBSToString modByteString 53 | -- Return the optimized module 54 | return optmod 55 | else 56 | if compileFile && file /= "" 57 | then do 58 | let llvmSrc = fileNameLLVM file 59 | let objectFile = fileWithoutExtension file 60 | modByteString <- moduleLLVMAssembly m 61 | writeLLVM (modBSToString modByteString) llvmSrc 62 | compileLLVMWithClang llvmSrc objectFile 63 | return optmod 64 | else return optmod 65 | where 66 | modBSToString modByteString = map (toEnum . fromIntegral) (BS.unpack modByteString) 67 | 68 | fileNameLLVM :: String -> String 69 | fileNameLLVM file = fileWithoutExtension file ++ ".ll" 70 | 71 | fileWithoutExtension :: String -> String 72 | fileWithoutExtension = reverse . tail . dropWhile (/= '.') . reverse 73 | 74 | writeLLVM :: String -> String -> IO () 75 | writeLLVM moduleSrc fileName = do 76 | writeFile fileName moduleSrc 77 | 78 | -- usage: cabal run kaleidoscope-fing -- -f ./test/programs/add_int_int.k -c 79 | -- clang /kaleidoscope/out.ll -o my_program -L/usr/lib -lstdlib -o outprogram 80 | -- ./outprogram.o 81 | compileLLVMWithClang :: String -> String -> IO () 82 | compileLLVMWithClang fileNameLlvm fileNameExecutable = do 83 | _ <- system cmd 84 | putStrLn cmd 85 | return () 86 | where 87 | cmd = "clang " ++ fileNameLlvm ++ " -o " ++ fileNameExecutable 88 | 89 | runJIT :: AST.Module -> IO String 90 | runJIT astModule = do 91 | withContext $ \context -> 92 | jit context 0 $ \executionEngine -> 93 | withModuleFromAST context astModule $ \m -> 94 | EE.withModuleInEngine executionEngine m $ \ee -> do 95 | mainFn <- EE.getFunction ee "main" 96 | case mainFn of 97 | Just fn -> do 98 | putStr $ if show (runInteger fn) == "" then "Error" else "\n" 99 | return $ show (runInteger fn) 100 | Nothing -> return "0" 101 | -------------------------------------------------------------------------------- /kaleidoscope/src/CodeGen/LocalVar.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DerivingStrategies #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | module CodeGen.LocalVar where 5 | 6 | import Data.ByteString.Short (ShortByteString) 7 | import qualified Data.List as List 8 | import Data.String (IsString (fromString)) 9 | import qualified Data.Text as T 10 | import LLVM.AST as AST hiding (function) 11 | import qualified LLVM.AST.Constant as C 12 | import LLVM.AST.Type (ptr) 13 | import qualified LLVM.AST.Type as ASTType 14 | 15 | type LocalVar = (Maybe ShortByteString, AST.Operand) -- alias, value 16 | 17 | localVarsFallback :: [AST.Operand] -> [LocalVar] 18 | localVarsFallback = map (\operand -> (Nothing, operand)) 19 | 20 | getLocalVarByName :: ShortByteString -> [LocalVar] -> Maybe LocalVar 21 | getLocalVarByName name = List.find (`matchName` name) 22 | where 23 | matchName :: LocalVar -> ShortByteString -> Bool 24 | matchName (Just _, ConstantOperand (C.GlobalReference PointerType {pointerReferent = ASTType.FunctionType {}, pointerAddrSpace = _} (Name funName))) n = funName == n 25 | matchName (Just varName, _) n = varName == n 26 | matchName (Nothing, LocalReference _ (Name varName)) n = removeEnding varName == n 27 | matchName (Nothing, LocalReference _ (UnName varNumber)) n = show varNumber == show n 28 | matchName _ _ = False 29 | -- TODO: Rework this function later, don't use show 30 | -- bytestring > 11.smth has implemented this function but llvm-hs 12 doesn't permit bytestring > 11 31 | removeEnding :: ShortByteString -> ShortByteString 32 | removeEnding variableName 33 | | T.isInfixOf "_" (T.pack $ show variableName) = fromString $ tail $ reverse $ tail $ dropWhile (/= '_') (reverse $ show variableName) 34 | | otherwise = variableName 35 | 36 | getFunctionOperand :: Name -> AST.Type -> ([Parameter], Bool) -> AST.Operand 37 | getFunctionOperand fn retType (params, _) = ConstantOperand $ C.GlobalReference (ptr $ FunctionType retType (map (\(AST.Parameter t _ _) -> t) params) False) fn -------------------------------------------------------------------------------- /kaleidoscope/src/CodeGen/Utils/Types.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module CodeGen.Utils.Types where 4 | 5 | import Data.List (find) 6 | import qualified LLVM.AST as AST 7 | import LLVM.AST.AddrSpace (AddrSpace (AddrSpace)) 8 | import qualified LLVM.AST.Constant as AST.Constant 9 | import qualified LLVM.AST.Type as ASTType 10 | import qualified Syntax as S 11 | 12 | type CurrentDef = (AST.Name, S.Type) 13 | 14 | -- TODO: probably missing some cases 15 | astTypeToSyntaxType :: ASTType.Type -> S.Type 16 | astTypeToSyntaxType t = case t of 17 | ASTType.FloatingPointType {ASTType.floatingPointType = ASTType.DoubleFP} -> S.Double 18 | ASTType.IntegerType {ASTType.typeBits = 32} -> S.Integer 19 | ASTType.IntegerType {ASTType.typeBits = 1} -> S.Boolean 20 | ASTType.StructureType {ASTType.elementTypes = [t1, t2]} -> S.Tuple (astTypeToSyntaxType t1) (astTypeToSyntaxType t2) 21 | ASTType.VoidType -> S.Void 22 | _ -> error $ "Unsupported type " ++ show t 23 | 24 | syntaxTypeToASTType :: S.Type -> AST.Type 25 | syntaxTypeToASTType S.Double = ASTType.double 26 | syntaxTypeToASTType S.Integer = ASTType.i32 27 | syntaxTypeToASTType S.Boolean = ASTType.i1 28 | syntaxTypeToASTType (S.Tuple t1 t2) = ASTType.PointerType (ASTType.StructureType False [syntaxTypeToASTType t1, syntaxTypeToASTType t2]) (AddrSpace 0) 29 | syntaxTypeToASTType (S.ListType t) = ASTType.PointerType (ASTType.StructureType False [syntaxTypeToASTType t, ASTType.ptr ASTType.void]) (AddrSpace 0) 30 | syntaxTypeToASTType (S.FunType argTypes retType) = ASTType.ptr (ASTType.FunctionType {ASTType.resultType = syntaxTypeToASTType retType, ASTType.argumentTypes = map syntaxTypeToASTType argTypes, ASTType.isVarArg = False}) 31 | syntaxTypeToASTType S.Void = ASTType.VoidType 32 | 33 | getExpressionType :: S.Expr -> [CurrentDef] -> AST.Type 34 | getExpressionType (S.Int _) _ = ASTType.i32 35 | getExpressionType (S.Float _) _ = ASTType.double 36 | getExpressionType (S.Bool _) _ = ASTType.i1 37 | getExpressionType (S.Call functionName _) currentDefs = syntaxTypeToASTType $ findLocalVarType currentDefs functionName 38 | getExpressionType (S.Var varName) currentDefs = syntaxTypeToASTType $ findLocalVarType currentDefs varName 39 | getExpressionType (S.UnaryOp unOp (S.TupleI e1 e2)) currentDefs = 40 | case unOp of 41 | "fst" -> getExpressionType e1 currentDefs 42 | "snd" -> getExpressionType e2 currentDefs 43 | _ -> error "Unsupported unary operation on Tuple" 44 | getExpressionType (S.UnaryOp unOp (S.List (x : xs))) currentDefs = 45 | case unOp of 46 | "head" -> getExpressionType x currentDefs 47 | "tail" -> getExpressionType (S.List xs) currentDefs 48 | _ -> error "Unsupported unary operation on List" 49 | getExpressionType (S.UnaryOp unOp e) currentDefs = 50 | case unOp of 51 | "!" -> ASTType.i1 52 | "-" -> getExpressionType e currentDefs 53 | _ -> getExpressionType e currentDefs 54 | -- TODO: this is potentially O(2^n)!!! 55 | getExpressionType (S.BinOp name a b) currentDefs 56 | | name == ":" = typeOfB 57 | | name `elem` ["==", "!=", "<", ">", "<=", ">="] = ASTType.i1 58 | | typeOfA == ASTType.double || typeOfB == ASTType.double = ASTType.double 59 | | otherwise = typeOfA 60 | where 61 | typeOfA = getExpressionType a currentDefs 62 | typeOfB = getExpressionType b currentDefs 63 | -- FIXME: fix this crappy current defs handling 64 | getExpressionType (S.Let varName varExpr e) currentDefs = getExpressionType e $ currentDefs ++ [(varName, astTypeToSyntaxType $ getExpressionType varExpr currentDefs)] 65 | getExpressionType (S.If _ e1 e2) currentDefs = 66 | if e1Type == getExpressionType e2 currentDefs 67 | then e1Type 68 | else error "Types of both sides of if statement should be the same" 69 | where 70 | e1Type = getExpressionType e1 currentDefs 71 | getExpressionType (S.List (x : rest)) currentDefs = do 72 | ASTType.PointerType (ASTType.StructureType False [getExpressionType x currentDefs, getExpressionType (S.List rest) currentDefs]) (AddrSpace 0) 73 | getExpressionType (S.List []) _ = ASTType.PointerType ASTType.VoidType (AddrSpace 0) 74 | getExpressionType (S.TupleI e1 e2) currentDefs = ASTType.PointerType (ASTType.StructureType False [getExpressionType e1 currentDefs, getExpressionType e2 currentDefs]) (AddrSpace 0) 75 | 76 | findLocalVarType :: [CurrentDef] -> AST.Name -> S.Type 77 | findLocalVarType currentDefs varName = case find (\(n, _) -> n == varName) currentDefs of 78 | Just (_, t) -> t 79 | Nothing -> error $ "Cannot determine type of variable " ++ show varName 80 | 81 | operandType :: AST.Operand -> AST.Type 82 | operandType op = case op of 83 | AST.LocalReference ty _ -> ty 84 | AST.ConstantOperand con -> case con of 85 | AST.Constant.Int 32 _ -> ASTType.i32 86 | AST.Constant.Int 1 _ -> ASTType.i1 87 | AST.Constant.Float _ -> ASTType.double 88 | AST.Constant.Null ty -> ASTType.PointerType ty (AddrSpace 0) 89 | _ -> error $ "Unsupported constant operand type: " ++ show op 90 | _ -> error $ "Unsupported operand type: " ++ show op -------------------------------------------------------------------------------- /kaleidoscope/src/Main.hs: -------------------------------------------------------------------------------- 1 | -- {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import CLIParameters (CLIParameters (..), parserParameters) 6 | import Control.Monad (void) 7 | import Control.Monad.Trans (MonadIO (liftIO)) 8 | import Data.Text (pack, strip, unpack) 9 | import qualified LLVM.AST as AST (Definition) 10 | import Options.Applicative 11 | import Processor (process) 12 | import StdLib.GenLibs (generateLibraries) 13 | import System.Console.Haskeline (InputT, defaultSettings, getInputLine, outputStr, outputStrLn, runInputT) 14 | 15 | main :: IO () 16 | main = do 17 | cliParameters <- execParser parserInfo 18 | case inputFile cliParameters of 19 | [] -> startRepl cliParameters 20 | fname -> void (processFile fname cliParameters) 21 | 22 | parserInfo :: ParserInfo CLIParameters 23 | parserInfo = 24 | info 25 | (parserParameters <**> helper) 26 | (fullDesc <> progDesc "Kaleidoscope compiler" <> header "Kaleidoscope compiler") 27 | 28 | startRepl :: CLIParameters -> IO () 29 | startRepl cliParameters = do 30 | libs <- generateLibraries 31 | runInputT defaultSettings (loop libs) 32 | where 33 | loop oldDefs = do 34 | outputStr "ready> " 35 | minput <- getNextInput 36 | case minput of 37 | Nothing -> outputStrLn "Goodbye." 38 | Just input -> do 39 | case unpack $ strip $ pack input of 40 | (':' : 'l' : ' ' : fileName) -> do 41 | maybeDefs <- liftIO $ processFile cleanFileName cliParameters 42 | case maybeDefs of 43 | Just defs -> loop defs 44 | Nothing -> loop oldDefs 45 | where 46 | -- because ";" must be present in the end of the line 47 | cleanFileName = removeLast fileName 48 | removeLast :: String -> String 49 | removeLast [] = [] 50 | removeLast [_] = [] 51 | removeLast (x : xs) = x : removeLast xs 52 | _ -> do 53 | maybeDefs <- liftIO $ process oldDefs input cliParameters 54 | case maybeDefs of 55 | Just defs -> do 56 | loop defs 57 | Nothing -> loop oldDefs 58 | 59 | getNextInput :: InputT IO (Maybe String) 60 | getNextInput = do 61 | nextInputLine <- getInputLine "" 62 | case nextInputLine of 63 | Just line -> case lastCharOrEmpty line of 64 | ';' -> return $ Just line 65 | _ -> do 66 | nextLine <- getNextInput 67 | case nextLine of 68 | Nothing -> return $ Just line 69 | Just next -> return $ Just $ line ++ ' ' : next 70 | Nothing -> return Nothing 71 | where 72 | lastCharOrEmpty :: String -> Char 73 | lastCharOrEmpty [] = ' ' 74 | lastCharOrEmpty s = last s 75 | 76 | processFile :: String -> CLIParameters -> IO (Maybe [AST.Definition]) 77 | processFile fname cliParameters = do 78 | file <- readFile fname 79 | libs <- generateLibraries 80 | process libs file cliParameters -------------------------------------------------------------------------------- /kaleidoscope/src/Parser/Lexer.hs: -------------------------------------------------------------------------------- 1 | module Parser.Lexer where 2 | 3 | import Control.Applicative (many, (<|>)) 4 | import Text.Parsec.Language (emptyDef) 5 | import Text.Parsec.String (Parser) 6 | import qualified Text.Parsec.Token as Tok 7 | 8 | lexer :: Tok.TokenParser () 9 | lexer = Tok.makeTokenParser style 10 | where 11 | ops = ["+", "*", "-", "/", "%", ":", ";", ",", "<", ">", "|", "->"] 12 | names = ["def", "extern", "if", "then", "else", "binary", "unary", "in", "for", "fun"] 13 | style = 14 | emptyDef 15 | { Tok.commentLine = "#", 16 | Tok.reservedOpNames = ops, 17 | Tok.reservedNames = names 18 | } 19 | 20 | int :: Parser Integer 21 | int = Tok.integer lexer 22 | 23 | float :: Parser Double 24 | float = Tok.float lexer 25 | 26 | bool :: Parser Bool 27 | bool = Tok.lexeme lexer $ (True <$ Tok.symbol lexer "true") <|> (False <$ Tok.symbol lexer "false") 28 | 29 | identifier :: Parser String 30 | identifier = Tok.identifier lexer 31 | 32 | parens :: Parser a -> Parser a 33 | parens = Tok.parens lexer 34 | 35 | brackets :: Parser a -> Parser a 36 | brackets = Tok.brackets lexer 37 | 38 | semiSep :: Parser a -> Parser [a] 39 | semiSep = Tok.semiSep lexer 40 | 41 | commaSep :: Parser a -> Parser [a] 42 | commaSep = Tok.commaSep lexer 43 | 44 | reserved :: String -> Parser () 45 | reserved = Tok.reserved lexer 46 | 47 | reservedOp :: String -> Parser () 48 | reservedOp = Tok.reservedOp lexer 49 | 50 | operator :: Parser String 51 | operator = do 52 | c <- Tok.opStart emptyDef 53 | cs <- many $ Tok.opLetter emptyDef 54 | return (c : cs) 55 | 56 | whitespace :: Parser () 57 | whitespace = Tok.whiteSpace lexer 58 | -------------------------------------------------------------------------------- /kaleidoscope/src/Parser/Parse.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Parser.Parse where 4 | 5 | import Data.Bifunctor (second) 6 | import Data.Functor.Identity (Identity) 7 | import Data.String (IsString (fromString)) 8 | import LLVM.AST.Name (Name) 9 | import qualified LLVM.IRBuilder.Module as M 10 | import qualified Parser.Lexer as L 11 | import qualified Syntax as S (Declaration (..), Expr (..), TopLevel (..), Type (..)) 12 | import Text.Parsec 13 | ( ParseError, 14 | eof, 15 | many, 16 | optionMaybe, 17 | parse, 18 | try, 19 | (<|>), 20 | ) 21 | import qualified Text.Parsec.Expr as Ex 22 | import Text.Parsec.String (Parser) 23 | import qualified Text.Parsec.Token as Tok 24 | 25 | binary :: String -> Ex.Assoc -> Ex.Operator String () Identity S.Expr 26 | binary s = Ex.Infix (L.reservedOp s >> return (S.BinOp (fromString s))) 27 | 28 | unary :: String -> Ex.Operator String () Identity S.Expr 29 | unary s = Ex.Prefix (L.reservedOp s >> return (S.UnaryOp (fromString s))) 30 | 31 | unops :: Ex.OperatorTable String () Identity S.Expr 32 | unops = 33 | [ [unary "!"], 34 | [unary "-"], 35 | [ unary "fst", 36 | unary "snd" 37 | ], 38 | [ unary "head", 39 | unary "tail" 40 | ] 41 | ] 42 | 43 | binops :: Ex.OperatorTable String () Identity S.Expr 44 | binops = 45 | [ [ binary "*" Ex.AssocLeft, 46 | binary "/" Ex.AssocLeft, 47 | binary "%" Ex.AssocLeft 48 | ], 49 | [ binary "+" Ex.AssocLeft, 50 | binary "-" Ex.AssocLeft 51 | ], 52 | [ binary "<" Ex.AssocLeft, 53 | binary ">" Ex.AssocLeft, 54 | binary "<=" Ex.AssocLeft, 55 | binary ">=" Ex.AssocLeft, 56 | binary "==" Ex.AssocLeft, 57 | binary "!=" Ex.AssocLeft 58 | ], 59 | [ binary "^^" Ex.AssocLeft, 60 | binary "&&" Ex.AssocLeft, 61 | binary "||" Ex.AssocLeft 62 | ] 63 | ] 64 | 65 | op :: Parser Name 66 | op = do 67 | L.whitespace 68 | o <- L.operator 69 | L.whitespace 70 | return (fromString o) 71 | 72 | unop :: Ex.Operator String () Identity S.Expr 73 | unop = Ex.Prefix (S.UnaryOp <$> op) 74 | 75 | binop :: Ex.Operator String () Identity S.Expr 76 | binop = Ex.Infix (S.BinOp <$> op) Ex.AssocLeft 77 | 78 | tp :: Parser S.Type 79 | tp = do 80 | try double 81 | <|> try integer 82 | <|> try boolean 83 | <|> try tupleT 84 | <|> try listT 85 | <|> try funT 86 | 87 | argument :: Parser (S.Type, String) 88 | argument = do 89 | t <- tp 90 | n <- L.identifier 91 | return (t, n) 92 | 93 | double :: Parser S.Type 94 | double = L.reserved "double" >> return S.Double 95 | 96 | integer :: Parser S.Type 97 | integer = L.reserved "int" >> return S.Integer 98 | 99 | boolean :: Parser S.Type 100 | boolean = L.reserved "bool" >> return S.Boolean 101 | 102 | tupleT :: Parser S.Type 103 | tupleT = do 104 | L.reserved "tuple" 105 | types <- L.parens $ L.commaSep tp 106 | return $ S.Tuple (head types) (head $ tail types) 107 | 108 | listT :: Parser S.Type 109 | listT = do 110 | listTp <- L.brackets tp 111 | return $ S.ListType listTp 112 | 113 | funT :: Parser S.Type 114 | funT = do 115 | L.reserved "fun" 116 | args <- L.parens $ L.commaSep tp 117 | L.reserved "->" 118 | S.FunType args <$> tp 119 | 120 | int :: Parser S.Expr 121 | int = 122 | S.Int <$> L.int 123 | 124 | floating :: Parser S.Expr 125 | floating = 126 | S.Float <$> L.float 127 | 128 | bool :: Parser S.Expr 129 | bool = 130 | S.Bool <$> L.bool 131 | 132 | tuple :: Parser S.Expr 133 | tuple = do 134 | elements <- L.parens $ L.commaSep expr 135 | case elements of 136 | [frst, scnd] -> return $ S.TupleI frst scnd 137 | _ -> fail "tuples must have exactly two elements" 138 | 139 | list :: Parser S.Expr 140 | list = do 141 | elements <- L.brackets $ L.commaSep expr 142 | return $ S.List elements 143 | 144 | expr :: Parser S.Expr 145 | expr = Ex.buildExpressionParser (binops ++ unops ++ [[unop], [binop]]) factor 146 | 147 | variable :: Parser S.Expr 148 | variable = S.Var . fromString <$> L.identifier 149 | 150 | extern :: Parser S.Declaration 151 | extern = do 152 | L.reserved "extern" 153 | name <- L.identifier 154 | arguments <- L.parens $ L.commaSep argument 155 | L.reserved "->" 156 | S.Extern (fromString name) (second fromString <$> arguments) <$> tp 157 | 158 | function :: Parser S.Declaration 159 | function = do 160 | L.reserved "def" 161 | name <- L.identifier 162 | arguments <- L.parens $ L.commaSep argument 163 | L.reserved "->" 164 | retType <- tp 165 | L.reserved ":" 166 | S.Function (fromString name) (second (M.ParameterName . fromString) <$> arguments) retType <$> expr 167 | 168 | call :: Parser S.Expr 169 | call = do 170 | name <- L.identifier 171 | -- parenthesis are optional for functions without arguments 172 | arguments <- L.parens $ L.commaSep expr 173 | return $ S.Call (fromString name) arguments 174 | 175 | ifthen :: Parser S.Expr 176 | ifthen = do 177 | L.reserved "if" 178 | cond <- expr 179 | L.reserved "then" 180 | thenTopLevel <- expr 181 | L.reserved "else" 182 | S.If cond thenTopLevel <$> expr 183 | 184 | letins :: Parser S.Expr 185 | letins = do 186 | L.reserved "let" 187 | defs <- L.commaSep $ do 188 | var <- L.identifier 189 | L.reservedOp "=" 190 | val <- expr 191 | return (fromString var, val) 192 | L.reserved "in" 193 | body <- expr 194 | return $ foldr (uncurry S.Let) body defs 195 | 196 | factor :: Parser S.Expr 197 | factor = 198 | try floating 199 | <|> try int 200 | <|> try bool 201 | <|> try tuple 202 | <|> try list 203 | <|> try call 204 | <|> try ifthen 205 | <|> try letins 206 | <|> variable 207 | <|> L.parens expr 208 | 209 | parseDeclaration :: Parser S.Declaration 210 | parseDeclaration = try function <|> try extern 211 | 212 | parseTopLevel :: Parser S.TopLevel 213 | parseTopLevel = do 214 | declaration <- optionMaybe parseDeclaration 215 | case declaration of 216 | Just d -> return $ S.Declaration d 217 | Nothing -> do 218 | S.Expr <$> (expr <|> factor) 219 | 220 | contents :: Parser a -> Parser a 221 | contents p = do 222 | Tok.whiteSpace L.lexer 223 | r <- p 224 | eof 225 | return r 226 | 227 | toplevel :: Parser [S.TopLevel] 228 | toplevel = many $ do 229 | def <- parseTopLevel 230 | L.reservedOp ";" 231 | return def 232 | 233 | parseToplevel :: String -> Either ParseError [S.TopLevel] 234 | parseToplevel = parse (contents toplevel) "" 235 | -------------------------------------------------------------------------------- /kaleidoscope/src/Processor.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Processor where 4 | 5 | import CLIParameters (CLIParameters (CLIParameters, compile, emitAST, failOnErrors, emitLlvmDefs)) 6 | import CodeGen.GenModule (genModule) 7 | import CodeGen.JIT (optimizeModule, runJIT) 8 | import LLVM.AST (Module (moduleDefinitions, moduleName), defaultModule) 9 | import qualified LLVM.AST as AST (Definition) 10 | import Parser.Parse (parseToplevel) 11 | 12 | process :: [AST.Definition] -> String -> CLIParameters -> IO (Maybe [AST.Definition]) 13 | process oldDefs newSource cliParameters = do 14 | let parsedSrc = parseToplevel newSource 15 | case parsedSrc of 16 | Left err -> do 17 | if failOnErrorsEnabled 18 | then error $ show err 19 | else print err >> return Nothing 20 | Right expressions -> do 21 | let defs = genModule oldDefs expressions 22 | case cliParameters of 23 | CLIParameters {emitAST = True} -> do 24 | putStrLn $ "Parsed expressions: " ++ show expressions 25 | _ -> return () 26 | case cliParameters of 27 | CLIParameters {emitLlvmDefs = True} -> do 28 | putStrLn $ "Last definition: " ++ show (last defs) 29 | _ -> return () 30 | 31 | -- Create module, compile it and execute it using the JIT 32 | let newModule = defaultModule {moduleName = "kaleidoscope", moduleDefinitions = defs} 33 | optimizedModule <- optimizeModule newModule cliParameters 34 | if compileEnabled 35 | then return $ Just defs 36 | else do 37 | _ <- runJIT optimizedModule 38 | return $ Just defs 39 | where 40 | CLIParameters {failOnErrors = failOnErrorsEnabled, compile = compileEnabled, emitAST = emitASTEnabled} = cliParameters 41 | -------------------------------------------------------------------------------- /kaleidoscope/src/StdLib/BaseDefs.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} 3 | 4 | module StdLib.BaseDefs where 5 | 6 | import Data.String (fromString) 7 | import LLVM.AST 8 | ( Definition (..), 9 | FloatingPointType (..), 10 | Name (..), 11 | Named (Do, (:=)), 12 | Operand (..), 13 | Parameter (..), 14 | Terminator (Ret), 15 | Type (..), 16 | mkName, 17 | operand0, 18 | returnOperand, 19 | ) 20 | import LLVM.AST.Attribute (FunctionAttribute (OptimizeNone)) 21 | import LLVM.AST.Global (BasicBlock (..), Global (..), functionDefaults) 22 | import qualified LLVM.AST.Instruction as I (Instruction (FPToSI, SIToFP, metadata, type'), Terminator (metadata')) 23 | import LLVM.AST.Linkage (Linkage (External)) 24 | import LLVM.AST.Type (i32, i8, ptr) 25 | 26 | baseDefinitions :: [Definition] 27 | baseDefinitions = 28 | [ GlobalDefinition 29 | functionDefaults 30 | { name = mkName "printf", 31 | linkage = External, 32 | parameters = ([Parameter ty (mkName "fmtStr") [] | ty <- [ptr i8]], True), 33 | returnType = i32, 34 | functionAttributes = [Right OptimizeNone] 35 | }, 36 | -- math functions 37 | GlobalDefinition 38 | functionDefaults 39 | { name = Name (fromString "sin"), 40 | parameters = ([Parameter (FloatingPointType DoubleFP) (Name (fromString "x")) []], False), 41 | returnType = FloatingPointType DoubleFP, 42 | basicBlocks = [] 43 | }, 44 | GlobalDefinition 45 | functionDefaults 46 | { name = Name (fromString "cos"), 47 | parameters = ([Parameter (FloatingPointType DoubleFP) (Name (fromString "x")) []], False), 48 | returnType = FloatingPointType DoubleFP, 49 | basicBlocks = [] 50 | }, 51 | GlobalDefinition 52 | functionDefaults 53 | { name = Name (fromString "tan"), 54 | parameters = ([Parameter (FloatingPointType DoubleFP) (Name (fromString "x")) []], False), 55 | returnType = FloatingPointType DoubleFP, 56 | basicBlocks = [] 57 | }, 58 | GlobalDefinition 59 | functionDefaults 60 | { name = Name (fromString "log"), 61 | parameters = ([Parameter (FloatingPointType DoubleFP) (Name (fromString "x")) []], False), 62 | returnType = FloatingPointType DoubleFP, 63 | basicBlocks = [] 64 | }, 65 | GlobalDefinition 66 | functionDefaults 67 | { name = Name (fromString "fabs"), 68 | parameters = ([Parameter (FloatingPointType DoubleFP) (Name (fromString "x")) []], False), 69 | returnType = FloatingPointType DoubleFP, 70 | basicBlocks = [] 71 | }, 72 | GlobalDefinition 73 | functionDefaults 74 | { name = Name (fromString "rand"), 75 | parameters = ([], False), 76 | returnType = IntegerType 32, 77 | basicBlocks = [] 78 | }, 79 | GlobalDefinition 80 | functionDefaults 81 | { name = Name (fromString "srand"), 82 | parameters = ([Parameter (IntegerType 32) (Name (fromString "seed")) []], False), 83 | returnType = IntegerType 32, 84 | basicBlocks = [] 85 | }, 86 | -- misc functions 87 | GlobalDefinition 88 | functionDefaults 89 | { name = Name (fromString "exit"), 90 | parameters = ([Parameter (IntegerType 32) (Name (fromString "status")) []], False), 91 | returnType = IntegerType 32, 92 | basicBlocks = [] 93 | }, 94 | 95 | -- type casting functions 96 | GlobalDefinition 97 | functionDefaults 98 | { name = Name (fromString "int_to_double"), 99 | parameters = ([Parameter (IntegerType {typeBits = 32}) (Name "x_0") []], False), 100 | returnType = FloatingPointType DoubleFP, 101 | basicBlocks = 102 | [ BasicBlock 103 | (UnName 0) 104 | [ UnName 1 105 | := I.SIToFP 106 | { operand0 = LocalReference (IntegerType {typeBits = 32}) (Name "x_0"), 107 | I.type' = FloatingPointType {floatingPointType = DoubleFP}, 108 | I.metadata = [] 109 | } 110 | ] 111 | (Do (Ret {returnOperand = Just (LocalReference (FloatingPointType {floatingPointType = DoubleFP}) (UnName 1)), I.metadata' = []})) 112 | ] 113 | }, 114 | GlobalDefinition 115 | functionDefaults 116 | { name = Name (fromString "double_to_int"), 117 | parameters = ([Parameter (FloatingPointType {floatingPointType = DoubleFP}) (Name "x_0") []], False), 118 | returnType = IntegerType {typeBits = 32}, 119 | basicBlocks = 120 | [ BasicBlock 121 | (UnName 0) 122 | [ UnName 1 123 | := I.FPToSI 124 | { operand0 = LocalReference (FloatingPointType {floatingPointType = DoubleFP}) (Name "x_0"), 125 | I.type' = IntegerType {typeBits = 32}, 126 | I.metadata = [] 127 | } 128 | ] 129 | (Do (Ret {returnOperand = Just (LocalReference (IntegerType {typeBits = 32}) (UnName 1)), I.metadata' = []})) 130 | ] 131 | } 132 | ] 133 | -------------------------------------------------------------------------------- /kaleidoscope/src/StdLib/GenLibs.hs: -------------------------------------------------------------------------------- 1 | module StdLib.GenLibs where 2 | 3 | import CLIParameters (CLIParameters (..)) 4 | import Data.List (isSuffixOf) 5 | import LLVM.AST (Definition) 6 | import Processor (process) 7 | import StdLib.BaseDefs (baseDefinitions) 8 | import System.Directory (getDirectoryContents) 9 | 10 | generateLibraries :: IO [Definition] 11 | generateLibraries = do 12 | source <- generateSource 13 | processLibrary source 14 | 15 | generateSource :: IO String 16 | generateSource = do 17 | files <- libFiles 18 | sources <- mapM readFile files 19 | return $ unlines sources 20 | 21 | processLibrary :: String -> IO [Definition] 22 | processLibrary source = do 23 | result <- process baseDefinitions "" (CLIParameters {inputFile = "", failOnErrors = False, optimizationLevel = 3, emitLLVM = False, emitAST = False, emitLlvmDefs = False, compile = False}) 24 | case result of 25 | Just definitions -> return definitions 26 | Nothing -> error "Could not process library" 27 | 28 | libFiles :: IO [String] 29 | libFiles = do 30 | let libDir = "./src/StdLib/lib" 31 | files <- getDirectoryContents libDir 32 | return $ map ((libDir ++ "/") ++) (filter (\s -> ".k" `isSuffixOf` s) files) 33 | -------------------------------------------------------------------------------- /kaleidoscope/src/StdLib/lib/list.k: -------------------------------------------------------------------------------- 1 | def length([int] l) -> int: if l == [] then 0 else 1 + length(tail(l)); 2 | 3 | def all([int] l, fun (int) -> bool f) -> bool: 4 | if l == [] then 5 | true 6 | else 7 | (if f(head l) then 8 | all(tail l, f) 9 | else 10 | false); 11 | 12 | def any([int] l, fun (int) -> bool f) -> bool: 13 | if l == [] then 14 | false 15 | else 16 | (if f(head l) then 17 | true 18 | else 19 | any(tail l, f)); 20 | 21 | def map_int([int] l, fun (int) -> int f) -> [int]: 22 | if l == [] then 23 | [] 24 | else 25 | f(head l) : map_int(tail l, f); 26 | 27 | def filter_int([int] l, fun (int) -> bool f) -> [int]: 28 | if l == [] then 29 | [] 30 | else 31 | (if f(head l) then 32 | head l : filter_int(tail l, f) 33 | else 34 | filter_int(tail l, f)); 35 | 36 | def nth_int([int] l, int n) -> int: 37 | if n == 0 then 38 | head l 39 | else 40 | nth_int(tail l, n - 1); 41 | 42 | def reverse_acc_int([int] l, [int] acc) -> [int]: 43 | if l == [] then 44 | acc 45 | else 46 | reverse_acc_int(tail l, head l : acc); 47 | 48 | def reverse_int([int] l) -> [int]: 49 | reverse_acc_int(l, []); 50 | 51 | def foldl_int([int] l, int acc, fun (int, int) -> int f) -> int: 52 | if l == [] then 53 | acc 54 | else 55 | foldl_int(tail l, f(acc, head l), f); 56 | 57 | def foldr_int([int] l, int acc, fun (int, int) -> int f) -> int: 58 | if l == [] then 59 | acc 60 | else 61 | f(head l, foldr_int(tail l, acc, f)); -------------------------------------------------------------------------------- /kaleidoscope/src/Syntax.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DerivingStrategies #-} 2 | 3 | module Syntax where 4 | 5 | import LLVM.AST.Name (Name) 6 | import LLVM.IRBuilder.Module (ParameterName) 7 | 8 | data TopLevel 9 | = Expr Expr 10 | | Declaration Declaration 11 | deriving stock (Eq, Ord, Show) 12 | 13 | data Expr 14 | = Int Integer 15 | | Float Double 16 | | Bool Bool 17 | | TupleI Expr Expr 18 | | List [Expr] 19 | | Let Name Expr Expr 20 | | Var Name 21 | | Call Name [Expr] 22 | | If Expr Expr Expr 23 | | UnaryOp Name Expr 24 | | BinOp Name Expr Expr 25 | deriving stock (Eq, Ord, Show) 26 | 27 | data Declaration 28 | = Function Name [(Type, ParameterName)] Type Expr 29 | | Extern Name [(Type, ParameterName)] Type 30 | deriving stock (Eq, Ord, Show) 31 | 32 | data Type 33 | = Double 34 | | Integer 35 | | Boolean 36 | | Tuple Type Type 37 | | ListType Type 38 | | FunType [Type] Type 39 | | Void 40 | deriving stock (Eq, Ord, Show) -------------------------------------------------------------------------------- /kaleidoscope/test/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import Control.Monad (void) 6 | import Data.List (isSuffixOf) 7 | import LLVM.IRBuilder.Module (buildModule) 8 | import System.Directory (doesFileExist, getDirectoryContents, listDirectory) 9 | import System.Exit (ExitCode (ExitSuccess)) 10 | import System.FilePath (()) 11 | import System.Process (system) 12 | import Test.Tasty (TestTree, defaultMain, localOption, testGroup) 13 | import Test.Tasty.HUnit (testCase, (@?=)) 14 | import Test.Tasty.Runners (NumThreads (NumThreads)) 15 | 16 | -- Main test suite 17 | main :: IO () 18 | main = do 19 | files <- listDirectory programDir 20 | let testFiles = filterProgramFiles files 21 | putStrLn $ "Found " ++ show (length testFiles) ++ " test files." 22 | 23 | let testCases = map generateOptimizationVariants testFiles 24 | defaultMain $ localOption (NumThreads 1) $ testGroup "Program Tests" testCases 25 | 26 | -- Directory paths 27 | programDir :: FilePath 28 | programDir = "./test/programs" 29 | 30 | outputDir :: FilePath 31 | outputDir = "./test/output" 32 | 33 | tempOutput :: FilePath 34 | tempOutput = "./test/tmp.out" 35 | 36 | silentCabal :: String 37 | silentCabal = "cabal run -v0 kaleidoscope-fing -- --file=" 38 | 39 | -- tests :: TestTree 40 | -- tests = testGroup "Tests" [programTests] 41 | 42 | filterProgramFiles :: [String] -> [String] 43 | filterProgramFiles = filter (\s -> ".k" `isSuffixOf` s) 44 | 45 | generateOptimizationVariants :: FilePath -> TestTree 46 | generateOptimizationVariants file = testGroup file $ map (generateTest file) ["-o0", "-o3"] 47 | 48 | -- Generate individual tests for each program file 49 | generateTest :: FilePath -> String -> TestTree 50 | generateTest file optLevel = testCase ("\t " ++ file ++ " " ++ optLevel) $ do 51 | let filePath = programDir file 52 | outputFilePath = outputDir file 53 | 54 | -- Run the test command 55 | exitCode <- system $ silentCabal ++ filePath ++ " " ++ optLevel ++ " --fail-on-errors > " ++ tempOutput 56 | exitCode @?= ExitSuccess 57 | 58 | -- Read actual output 59 | actualOutput <- readFile tempOutput 60 | 61 | -- Check if expected output file exists 62 | fileExists <- doesFileExist outputFilePath 63 | if fileExists 64 | then do 65 | expectedOutput <- readFile outputFilePath 66 | actualOutput @?= expectedOutput 67 | else do 68 | putStrLn $ "No expected output file for " ++ file 69 | putStrLn $ "Writing actual output to " ++ outputFilePath 70 | writeFile outputFilePath actualOutput 71 | 72 | -- Final comparison to ensure correctness 73 | expectedOutput <- readFile outputFilePath 74 | actualOutput @?= expectedOutput 75 | 76 | -- Cleanup 77 | removeFile tempOutput 78 | 79 | removeFile :: FilePath -> IO () 80 | removeFile file = do 81 | fileExists <- doesFileExist file 82 | if fileExists 83 | then do 84 | system $ "rm " ++ file 85 | return () 86 | else return () 87 | 88 | -- TODO: REPL features tests 89 | -------------------------------------------------------------------------------- /kaleidoscope/test/generator/GenPrograms.hs: -------------------------------------------------------------------------------- 1 | module GenPrograms where 2 | 3 | import Data.List (intercalate) 4 | import System.Environment (getArgs) 5 | 6 | functionFromIndex :: Int -> String 7 | functionFromIndex i = "def f_" ++ show i ++ "(int x) -> int: x;" 8 | 9 | letInFromIndex :: Int -> String 10 | letInFromIndex i = intercalate (show i) ["let int var_", " = f_", "(", ") in"] 11 | 12 | letInsString :: Int -> String 13 | letInsString iterations = intercalate "\n" $ map letInFromIndex [1 .. iterations] 14 | 15 | functionDefsString :: Int -> String 16 | functionDefsString iterations = intercalate "\n" $ map functionFromIndex [1 .. iterations] 17 | 18 | operationsString :: Int -> String 19 | operationsString iterations = intercalate " + " $ map (\i -> "var_" ++ show i) [1 .. iterations] 20 | 21 | programString :: Int -> String 22 | programString iterations = functionDefsString iterations ++ "\n" ++ letInsString iterations ++ "\n" ++ operationsString iterations ++ ";" 23 | 24 | main :: IO () 25 | main = do 26 | args <- getArgs 27 | case args of 28 | [] -> writeFile "/kaleidoscope/test/generator/out.k" $ programString 100 29 | [iterations] -> writeFile "/kaleidoscope/test/generator/out.k" $ programString (read iterations) 30 | _ -> putStrLn "Usage: GenPrograms [iterations]" -------------------------------------------------------------------------------- /kaleidoscope/test/generator/generator.md: -------------------------------------------------------------------------------- 1 | generate programs to test performance 2 | 3 | `./test/generator/iterate.sh ` -------------------------------------------------------------------------------- /kaleidoscope/test/generator/iterate.sh: -------------------------------------------------------------------------------- 1 | iteration_count=$1 2 | step=$2 3 | 4 | for (( i=2; i <= $iteration_count; i+=$step )) 5 | do 6 | echo "iteration $i" 7 | # generate program 8 | runhaskell ./test/generator/GenPrograms.hs $i 9 | # run program and time execution 10 | time cabal run kaleidoscope-fing "./test/generator/out.k" 11 | done -------------------------------------------------------------------------------- /kaleidoscope/test/output/add_float_float.k: -------------------------------------------------------------------------------- 1 | 2 | 2.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/add_float_int.k: -------------------------------------------------------------------------------- 1 | 2 | 2.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/add_int_float.k: -------------------------------------------------------------------------------- 1 | 2 | 2.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/add_int_int.k: -------------------------------------------------------------------------------- 1 | 2 | 2 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/and_false_false.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/and_false_true.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/and_true_false.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/and_true_true.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/cons_add.k: -------------------------------------------------------------------------------- 1 | 2 | [8, 90] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/cons_function.k: -------------------------------------------------------------------------------- 1 | 2 | [99, 1, 2, 3] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/cons_functions.k: -------------------------------------------------------------------------------- 1 | 2 | [9.000000, 45.300000, 1.000000, 2.000000, 3.000000] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/cons_int.k: -------------------------------------------------------------------------------- 1 | 2 | [8, 55, 12, 100] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/const_float.k: -------------------------------------------------------------------------------- 1 | 2 | 10.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/const_int_float.k: -------------------------------------------------------------------------------- 1 | 2 | 6.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/const_int_int.k: -------------------------------------------------------------------------------- 1 | 2 | 16 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/cos.k: -------------------------------------------------------------------------------- 1 | 2 | -1.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/div_float_int.k: -------------------------------------------------------------------------------- 1 | 2 | 2.500000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/div_int_int.k: -------------------------------------------------------------------------------- 1 | 2 | 2 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/double_to_int.k: -------------------------------------------------------------------------------- 1 | 2 | 100 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/extern.k: -------------------------------------------------------------------------------- 1 | G 2 | 0 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fabs.k: -------------------------------------------------------------------------------- 1 | 2 | 99.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_add_float_float.k: -------------------------------------------------------------------------------- 1 | 2 | 3.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_add_float_int.k: -------------------------------------------------------------------------------- 1 | 2 | 3.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_add_int_int.k: -------------------------------------------------------------------------------- 1 | 2 | 3 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_create_list_bool.k: -------------------------------------------------------------------------------- 1 | 2 | [true, false, true, false, true] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_create_list_float.k: -------------------------------------------------------------------------------- 1 | 2 | [2.810000, 3.140000, 4.000000] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_create_list_int.k: -------------------------------------------------------------------------------- 1 | 2 | [5, 5, 5, 5, 5] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_div_int_int.k: -------------------------------------------------------------------------------- 1 | 2 | 2.500000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_int_float.k: -------------------------------------------------------------------------------- 1 | 2 | 3.500000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_nested.k: -------------------------------------------------------------------------------- 1 | 2 | 9 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_return_tuple.k: -------------------------------------------------------------------------------- 1 | 2 | (0.000000, 0.000000) 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fn_return_tuple_nested.k: -------------------------------------------------------------------------------- 1 | 2 | (3.400000, (5.600000, 7)) 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/foldl_int.k: -------------------------------------------------------------------------------- 1 | 2 | 90 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/foldr_int.k: -------------------------------------------------------------------------------- 1 | 2 | 106 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fst_float.k: -------------------------------------------------------------------------------- 1 | 2 | 9.990000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fst_int.k: -------------------------------------------------------------------------------- 1 | 2 | 9 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/fst_tuple.k: -------------------------------------------------------------------------------- 1 | 2 | (1, 2) 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/head_bool.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/head_float.k: -------------------------------------------------------------------------------- 1 | 2 | 2.300000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/head_int.k: -------------------------------------------------------------------------------- 1 | 2 | 6 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/higher_order_bool.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/higher_order_float.k: -------------------------------------------------------------------------------- 1 | 2 | 1.500000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/higher_order_int.k: -------------------------------------------------------------------------------- 1 | 2 | 27 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/if_float.k: -------------------------------------------------------------------------------- 1 | 2 | 2.500000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/if_int.k: -------------------------------------------------------------------------------- 1 | 2 | 10 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/if_nested.k: -------------------------------------------------------------------------------- 1 | 2 | 1234 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/int_to_double.k: -------------------------------------------------------------------------------- 1 | 2 | 5542.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/let_in_float.k: -------------------------------------------------------------------------------- 1 | 2 | 5.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/let_in_int.k: -------------------------------------------------------------------------------- 1 | 2 | 5 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/let_in_multiple.k: -------------------------------------------------------------------------------- 1 | 2 | 6 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/let_in_nested.k: -------------------------------------------------------------------------------- 1 | 2 | 6.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_all_false.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_all_true.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_bool.k: -------------------------------------------------------------------------------- 1 | 2 | [true, false] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_filter_int.k: -------------------------------------------------------------------------------- 1 | 2 | [2, 8, 10, 4] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_float.k: -------------------------------------------------------------------------------- 1 | 2 | [2.000000, 34.300000, 11.070000] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_int.k: -------------------------------------------------------------------------------- 1 | 2 | [1, 2, 3] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_int_constant.k: -------------------------------------------------------------------------------- 1 | 2 | [3, 4, 99, 25, 99] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_int_function.k: -------------------------------------------------------------------------------- 1 | 2 | [20, 11, 44, 100] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_map_int.k: -------------------------------------------------------------------------------- 1 | 2 | [20, 40, 100] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_max.k: -------------------------------------------------------------------------------- 1 | 2 | 60 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_nth_int.k: -------------------------------------------------------------------------------- 1 | 2 | 1 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/list_reverse_int.k: -------------------------------------------------------------------------------- 1 | 2 | [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/log.k: -------------------------------------------------------------------------------- 1 | 2 | 2.302585 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/negative_integer.k: -------------------------------------------------------------------------------- 1 | 2 | -10 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/not_false.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/not_true.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/or_false_false.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/or_false_true.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/or_true_false.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/or_true_true.k: -------------------------------------------------------------------------------- 1 | 2 | true 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/primes.k: -------------------------------------------------------------------------------- 1 | 2 | [47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/recursive_fib.k: -------------------------------------------------------------------------------- 1 | 2 | 8 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/recursive_sum.k: -------------------------------------------------------------------------------- 1 | 2 | 55 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/redefinition_function.k: -------------------------------------------------------------------------------- 1 | 2 | 1050 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/redefinition_function_recursive.k: -------------------------------------------------------------------------------- 1 | 2 | 55 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/sin.k: -------------------------------------------------------------------------------- 1 | 2 | 0.000093 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/snd_bool.k: -------------------------------------------------------------------------------- 1 | 2 | false 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/snd_float.k: -------------------------------------------------------------------------------- 1 | 2 | 13.450000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/snd_tuple.k: -------------------------------------------------------------------------------- 1 | 2 | (2, 3) 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tail_bool.k: -------------------------------------------------------------------------------- 1 | 2 | [true, false, true, false] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tail_float.k: -------------------------------------------------------------------------------- 1 | 2 | [6.000000, 7.000000, 8.000000, 9.000000] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tail_int.k: -------------------------------------------------------------------------------- 1 | 2 | [7, 8, 9] 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tan.k: -------------------------------------------------------------------------------- 1 | 2 | 0.000000 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tuple_max.k: -------------------------------------------------------------------------------- 1 | 2 | 33 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/output/tuple_nested.k: -------------------------------------------------------------------------------- 1 | 2 | (((1, 2.000000), (3.000000, (5, (6, 7.250000)))), (9, 10)) 3 | -------------------------------------------------------------------------------- /kaleidoscope/test/programs/add_float_float.k: -------------------------------------------------------------------------------- 1 | 1.0 + 1.0; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/add_float_int.k: -------------------------------------------------------------------------------- 1 | 1.0 + 1; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/add_int_float.k: -------------------------------------------------------------------------------- 1 | 1 + 1.0; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/add_int_int.k: -------------------------------------------------------------------------------- 1 | 1 + 1; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/and_false_false.k: -------------------------------------------------------------------------------- 1 | false && false; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/and_false_true.k: -------------------------------------------------------------------------------- 1 | false && true; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/and_true_false.k: -------------------------------------------------------------------------------- 1 | true && false; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/and_true_true.k: -------------------------------------------------------------------------------- 1 | true && true; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/cons_add.k: -------------------------------------------------------------------------------- 1 | 5 + 3:[90]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/cons_function.k: -------------------------------------------------------------------------------- 1 | def short_list() -> [int]: [1, 2, 3]; 2 | 3 | 99:short_list(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/cons_functions.k: -------------------------------------------------------------------------------- 1 | def foo() -> [double]: [1.0, 2.0, 3.0]; 2 | 3 | def bar() -> [double]: 45.3:foo(); 4 | 5 | def baz(double d) -> double: d; 6 | 7 | baz(9.0):bar(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/cons_int.k: -------------------------------------------------------------------------------- 1 | 8:[55, 12, 100]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/cos.k: -------------------------------------------------------------------------------- 1 | cos(3.1415); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/div_float_int.k: -------------------------------------------------------------------------------- 1 | 10.0 / 4; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/div_int_int.k: -------------------------------------------------------------------------------- 1 | 10 / 4; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/double_to_int.k: -------------------------------------------------------------------------------- 1 | double_to_int(100.99); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/extern.k: -------------------------------------------------------------------------------- 1 | extern putchari(int i) -> int; 2 | putchari(71); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fabs.k: -------------------------------------------------------------------------------- 1 | fabs(-99.0); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_add_float_float.k: -------------------------------------------------------------------------------- 1 | def add(double a, double b) -> double: a + b; 2 | 3 | add(1.0, 2.0); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_add_float_int.k: -------------------------------------------------------------------------------- 1 | def add(double a, int b) -> double: a + b; 2 | 3 | add(1.0, 2); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_add_int_int.k: -------------------------------------------------------------------------------- 1 | def add(int a, int b) -> int: a + b; 2 | 3 | add(1, 2); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_create_list_bool.k: -------------------------------------------------------------------------------- 1 | def bool_list() -> [bool]: [true, false, true, false, true]; 2 | 3 | bool_list(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_create_list_float.k: -------------------------------------------------------------------------------- 1 | def numbers() -> [double]: [2.81, 3.14, 4.0]; 2 | 3 | numbers(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_create_list_int.k: -------------------------------------------------------------------------------- 1 | def five_list() -> [int]: [5, 5, 5, 5, 5]; 2 | 3 | five_list(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_div_int_int.k: -------------------------------------------------------------------------------- 1 | def div_int(int a, int b) -> double: (a + 0.0) / b; 2 | 3 | div_int(10, 4); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_int_float.k: -------------------------------------------------------------------------------- 1 | def add_half(int a) -> double: a + 0.5; 2 | 3 | add_half(3); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_nested.k: -------------------------------------------------------------------------------- 1 | def add(int a, int b) -> int: a + b; 2 | def sub(int a, int b) -> int: a - b; 3 | 4 | add(5, sub(6, 2)); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_return_tuple.k: -------------------------------------------------------------------------------- 1 | def origin() -> tuple(double, double): 2 | (0.0, 0.0); 3 | 4 | origin(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fn_return_tuple_nested.k: -------------------------------------------------------------------------------- 1 | def some_numbers() -> tuple(double, tuple(double, tuple(double, int))): 2 | (1.2, (3.4, (5.6, 7))); 3 | 4 | snd some_numbers(); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/foldl_int.k: -------------------------------------------------------------------------------- 1 | def add(int a, int b) -> int: a + b; 2 | 3 | foldl_int([10, 50, 40], -10, add); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/foldr_int.k: -------------------------------------------------------------------------------- 1 | def add(int a, int b) -> int: a + b; 2 | 3 | foldr_int([1,2,3], 100, add); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fst_float.k: -------------------------------------------------------------------------------- 1 | fst (9.99, 100); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fst_int.k: -------------------------------------------------------------------------------- 1 | fst (9, 10); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/fst_tuple.k: -------------------------------------------------------------------------------- 1 | fst ((1,2), 3); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/head_bool.k: -------------------------------------------------------------------------------- 1 | head [false, true, false, true, false]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/head_float.k: -------------------------------------------------------------------------------- 1 | head [2.3, 6.1, 8.9, 9.0, 1.2]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/head_int.k: -------------------------------------------------------------------------------- 1 | head [6, 5, 1, 2, 3]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/higher_order_bool.k: -------------------------------------------------------------------------------- 1 | def checker(fun (int) -> bool check, int x) -> bool: check(x); 2 | 3 | def is_positive(int x) -> bool: x > 0; 4 | 5 | checker(is_positive, 3); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/higher_order_float.k: -------------------------------------------------------------------------------- 1 | def floater(fun (double) -> double g, double d) -> double: g(d); 2 | 3 | def half(double x) -> double: x / 2; 4 | 5 | floater(half, 3.0); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/higher_order_int.k: -------------------------------------------------------------------------------- 1 | def foo(fun (int) -> int g) -> int: g(9); 2 | 3 | def bar(int x) -> int: x * 3; 4 | 5 | foo(bar); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/if_float.k: -------------------------------------------------------------------------------- 1 | if (0) then -1.0 else 2.5; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/if_int.k: -------------------------------------------------------------------------------- 1 | if (0) then 4 else 10; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/if_nested.k: -------------------------------------------------------------------------------- 1 | def test(int a, int b) -> int: 2 | if a > 5 then 3 | if b > a then 1 else 2 4 | else 5 | if a > b then 3 else 4; 6 | 7 | 8 | 1000 * test(6, 7) + 100 * test(6, 1) + 10 * test(4, 1) + test(4, 7); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/int_to_double.k: -------------------------------------------------------------------------------- 1 | int_to_double(5542); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/let_in_float.k: -------------------------------------------------------------------------------- 1 | let a = 4.0 in a + 1; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/let_in_int.k: -------------------------------------------------------------------------------- 1 | let a = 4 in a + 1; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/let_in_multiple.k: -------------------------------------------------------------------------------- 1 | let a = 1, b = 2, c = 3 in 2 | a + b + c; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/let_in_nested.k: -------------------------------------------------------------------------------- 1 | let a = 1 in 2 | let b = 2.0 in 3 | let c = 3 in 4 | a + b + c; 5 | 6 | # let int a = 1 in let double b = 2.0 in let int c = 3 in a + b + c; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_all_false.k: -------------------------------------------------------------------------------- 1 | def even(int a) -> bool: a % 2 == 0; 2 | 3 | all([2, 5, 17, 8, 10], even); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_all_true.k: -------------------------------------------------------------------------------- 1 | def even(int a) -> bool: a % 2 == 0; 2 | 3 | all([2, 4, 6, 8, 10], even); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_bool.k: -------------------------------------------------------------------------------- 1 | [true, false]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_filter_int.k: -------------------------------------------------------------------------------- 1 | def even(int a) -> bool: a % 2 == 0; 2 | 3 | filter_int([2, 5, 17, 8, 10, 99, 4], even); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_float.k: -------------------------------------------------------------------------------- 1 | [2.0, 34.3, 11.07]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_int.k: -------------------------------------------------------------------------------- 1 | [1, 2, 3]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_int_function.k: -------------------------------------------------------------------------------- 1 | def foo(int x) -> int: x * 10; 2 | 3 | [foo(2), 1 + foo(1), 44, foo(foo(1))]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_map_int.k: -------------------------------------------------------------------------------- 1 | def double(int x) -> int: x * 2; 2 | 3 | map_int([10, 20, 50], double); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_max.k: -------------------------------------------------------------------------------- 1 | def list_max([int] l, int max) -> int: 2 | if l == [] then 3 | max 4 | else 5 | if (head l) > max then 6 | list_max(tail l, head l) 7 | else 8 | list_max(tail l, max); 9 | 10 | list_max([1, 2, 3, 4, 5, 60, 7, 8, 9, 10], 0); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_nth_int.k: -------------------------------------------------------------------------------- 1 | nth_int([3,4,1,2,5], 2); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/list_reverse_int.k: -------------------------------------------------------------------------------- 1 | reverse_int([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/log.k: -------------------------------------------------------------------------------- 1 | log(10.0); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/negative_integer.k: -------------------------------------------------------------------------------- 1 | -10; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/not_false.k: -------------------------------------------------------------------------------- 1 | !false; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/not_true.k: -------------------------------------------------------------------------------- 1 | !true; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/or_false_false.k: -------------------------------------------------------------------------------- 1 | false || false; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/or_false_true.k: -------------------------------------------------------------------------------- 1 | false || true; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/or_true_false.k: -------------------------------------------------------------------------------- 1 | true || false; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/or_true_true.k: -------------------------------------------------------------------------------- 1 | true || true; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/primes.k: -------------------------------------------------------------------------------- 1 | def divisibleAny(int n, int i) -> bool: 2 | if i < 2 then 3 | false 4 | else 5 | if n % i == 0 then 6 | true 7 | else 8 | divisibleAny(n, i - 1); 9 | 10 | 11 | def isPrime(int n) -> bool: !divisibleAny(n, n - 1); 12 | 13 | def primesUntil(int n) -> [int]: 14 | if n < 2 then 15 | [] 16 | else 17 | if isPrime(n) then 18 | n:primesUntil(n - 1) 19 | else 20 | primesUntil(n - 1); 21 | 22 | primesUntil(50); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/recursive_fib.k: -------------------------------------------------------------------------------- 1 | def fib(int x) -> int: 2 | if x < 3 then 3 | 1 4 | else 5 | fib(x-1) + fib(x-2); 6 | 7 | fib(6); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/recursive_sum.k: -------------------------------------------------------------------------------- 1 | def sum(int a) -> int: if (a == 0) then 0 else a + sum(a - 1); 2 | 3 | sum(10); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/redefinition_function.k: -------------------------------------------------------------------------------- 1 | def f(int a) -> int: a + 1; 2 | 3 | 4 | def f(int a) -> int: a + 1000; 5 | 6 | 7 | f(50); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/redefinition_function_recursive.k: -------------------------------------------------------------------------------- 1 | def sum(int a) -> int: 37; 2 | 3 | def sum(int a) -> int: if (a == 0) then 0 else a + sum(a - 1); 4 | 5 | sum(10); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/sin.k: -------------------------------------------------------------------------------- 1 | sin(3.1415); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/snd_bool.k: -------------------------------------------------------------------------------- 1 | snd (333, false); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/snd_float.k: -------------------------------------------------------------------------------- 1 | snd (9,13.45); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/snd_tuple.k: -------------------------------------------------------------------------------- 1 | snd (1, (2, 3)); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tail_bool.k: -------------------------------------------------------------------------------- 1 | tail [false, true, false, true, false]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tail_float.k: -------------------------------------------------------------------------------- 1 | tail [5.0, 6.0, 7.0, 8.0, 9.0]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tail_int.k: -------------------------------------------------------------------------------- 1 | tail [6,7,8,9]; -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tan.k: -------------------------------------------------------------------------------- 1 | tan(10); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tuple_max.k: -------------------------------------------------------------------------------- 1 | def max(tuple(int, int) x) -> int: 2 | if ((fst x) > (snd x)) then fst x else snd x; 3 | 4 | max((33, 1)); -------------------------------------------------------------------------------- /kaleidoscope/test/programs/tuple_nested.k: -------------------------------------------------------------------------------- 1 | (((1,2.0),(3.0, (5, (6, 7.25)))),(9,10)); -------------------------------------------------------------------------------- /notas/08-04-2023-dynamic-libraries.md: -------------------------------------------------------------------------------- 1 | # Funciones externas 2 | 3 | ## Solucion 4 | 5 | Kaleidoscope permit invocar funciones externa mediante la keyword `extern`. 6 | Estas funciones no se definend en nuestro lenguage sino que provienend de librerias que estan presentes en el sistema. 7 | 8 | Por ejemplo: 9 | ``` 10 | ; ModuleID = 'Kaleidoscope' 11 | 12 | declare double @sin(double) 13 | 14 | define double @main() { 15 | entry: 16 | %0 = call double @sin(double 1.000000e+00) 17 | ret double %0 18 | } 19 | ``` 20 | 21 | Se invoca a la funcion `sin` mediante `dlsym("sin")` en el proceso que esta corriendo Kaleidoscope. 22 | 23 | Con esto se puede invocar a librerias arbitrarias in importar en que lenguaje fueron implementadas, esto es de gran utilidad 24 | ya que es posible ejecutar codigo arbitrario directamente desde el interprete JIT de Kaleidoscope. 25 | 26 | En particular, se utilizarán funciones implementadas en C para las operaciones de entrada/salida como parte 27 | de la libreria estandar de Kaleidoscope. 28 | 29 | Esto requiere que se generen archivos con extension `.so` (shared objects) que deben estar presentes en el entorno 30 | de ejecución para poder utilizar las funciones definidas. La generacion de estos archivos se logra mediante gcc: 31 | `gcc -fPIC -shared /kaleidoscope/src/cbits/putchard.c -o /usr/lib/putchard.so` 32 | 33 | Este comando es ejecutado previo a la etapa de build de Kaleidoscope, en la cual se especifica este archivo 34 | como libreria dinamica en los parametros de ghc. 35 | 36 | 37 | ## Debugging 38 | 39 | Si la libreria no se encuentra enlazada correctamente, falla con un Segmentation Fault, lo cual es dificil de debuggear. 40 | 41 | Mediante las herramientas `ldd` en Linux o `otool -L` en macOS, se pueden ver cuales son las librerias dinamicas enlazadas a un ejecutable. 42 | 43 | Mediante Cabal, se pueden generar estas librerias desde un archivo .c, pero no se pudo lograr esto entonces se realizo como un paso extra en el Dockerfile (posible mejora aqui) 44 | 45 | 46 | Fuentes: 47 | - Capitulo 4 Kaleidoscope 48 | - https://stackoverflow.com/questions/9688200/difference-between-shared-objects-so-static-libraries-a-and-dlls-so 49 | - https://users.cs.utah.edu/~germain/PPS/Topics/C_Language/file_IO.html -------------------------------------------------------------------------------- /notas/13-12-2022.md: -------------------------------------------------------------------------------- 1 | # Notas 13-12-2022 2 | 3 | Estudiar las partes conceptuales, no estudiar todo a fondo. 4 | 5 | En febrero hacer una reunion y presentar lo que hemos aprendido. 6 | 7 | Ir documentando lo que vamos haciendo, ya que va todo al documento final, notas sobre 8 | 9 | ## Lenguaje funcional simple a probar: 10 | 11 | 1) Lenguaje minimal de expresiones: 12 | 13 | Lenguaje de expresiones con un let (un binding local) <- construcción interesante que muestra características del lenguaje 14 | Un let introduce un scope local, esto ya genera alguna característica. 15 | Implementar algún operador aritmético, como suma. 16 | 17 | If then else también, puede ser un if0 (permite no tener booleanos). 18 | 19 | Empezar con un tipo de datos y después agregar otro. 20 | 21 | Con una expresión principal MAIN que es la que se ejecuta. 22 | 23 | 2) Lenguaje con definiciones 24 | 25 | Con definición de funciones sin alto orden 26 | 27 | 3) Alto orden 28 | 29 | ## Observaciones: 30 | 31 | Revisar las etapas que pasaron los compiladores de GHC a LLVM. 32 | Puedo asumir que los tipos están bien, pensando que en una etapa anterior eso ya se chequeo. 33 | Los lenguajes intermedios deben ser simples para poder trabajar con ellos. 34 | -------------------------------------------------------------------------------- /notas/21-05-2023-interprete.md: -------------------------------------------------------------------------------- 1 | interprete 2 | 3 | 1. AST interpreter 4 | 5 | Agregar la expresion a la lista dentro del AST. 6 | Recompilar todo a llvm a partir del nuevo AST. 7 | Interprete necesita asignación -> Operador '=', se agrega un Let al AST y las siguientes instrucciones van todas dentro del L 8 | et. -------------------------------------------------------------------------------- /notas/compilacion-ll.md: -------------------------------------------------------------------------------- 1 | # Compilacion de archivos LLVM IR (.ll) 2 | 3 | ## Simple 4 | 5 | ``` 6 | gcc id.ll -o id 7 | ./id 8 | ``` 9 | 10 | ## Con librerias dinamicas (.so) 11 | 12 | ### Primero, generar un archivo .so, desde un archivo putchard.c 13 | 14 | Putchard.ll: 15 | 16 | ``` 17 | ; ModuleID = 'Kaleidoscope' 18 | source_filename = "" 19 | 20 | declare double @putchard(double) 21 | 22 | define double @main() { 23 | entry: 24 | %0 = call double @putchard(double 1.200000e+02) 25 | ret double %0 26 | } 27 | ``` 28 | Putchard.c (libreria) 29 | 30 | ``` 31 | /* putchard.c 32 | $ gcc -fPIC -shared putchard.c -o libputchard.so 33 | */ 34 | 35 | #include "stdio.h" 36 | 37 | // putchard - putchar that takes a double and returns 0. 38 | double putchard(double X) { 39 | putchar((char)X); 40 | fflush(stdout); 41 | return 0; 42 | } 43 | ``` 44 | 45 | - Importante: usar el prefijo 'lib' para el nombre del SO (shared object) 46 | 47 | - Establecer el path para que el sistema busque la libreria 48 | 49 | ``` 50 | LD_LIBRARY_PATH=/Users/fing/kaleidoscope/kaleidoscope/src/cbits 51 | DYLD_LIBRARY_PATH=/Users/fing/kaleidoscope/kaleidoscope/src/cbits 52 | ``` 53 | 54 | - Compilar con gcc 55 | 56 | `gcc -L/Users/fing/kaleidoscope/kaleidoscope/src/lib -Wall -o test putchard.ll -lputchard` 57 | 58 | `./test` 59 | 60 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LLVM+Haskell Kaleidoscope project 2 | 3 | Andrés Collares & Agustín Gazzano 4 | 5 | ## Requirements for working on the project 6 | 7 | - `stack` 8 | - `ghc-9.2.4` 9 | - [`llvm-hs`](https://hackage.haskell.org/package/llvm-hs) 10 | 11 | ## Linting and Formatting 12 | 13 | - [`haskell-language-server`](https://github.com/haskell/haskell-language-server) 14 | - [`ormolu`](https://github.com/tweag/ormolu) 15 | 16 | ## llvm-hs 17 | 18 | > TODO: Check if building llvm-hs-15 from source is better than using stack or cabal, it could also open the possibility to make changes and bugfixes using a fork. 19 | 20 | ## Docker 21 | 22 | ``` 23 | docker compose build 24 | docker compose up -d 25 | docker compose run project bash 26 | cabal run 27 | ``` 28 | 29 | ### Available options 30 | 31 | ``` 32 | cabal run kaleidoscope-fing -- --help 33 | ``` 34 | 35 | ### Running code samples 36 | 37 | ``` 38 | cabal run kaleidoscope-fing -- --file "./test/programs/recursive_fib.k" 39 | ``` 40 | 41 | ### Test suite 42 | 43 | ``` 44 | cabal test 45 | or to show progress: 46 | cabal test tests --test-show-detail=streaming 47 | ``` 48 | 49 | ### Running ghci through Cabal 50 | 51 | ``` 52 | cabal exec ghci 53 | or 54 | cabal repl 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /setup-macos.md: -------------------------------------------------------------------------------- 1 | https://github.com/sdiehl/kaleidoscope 2 | https://www.stephendiehl.com/llvm/ 3 | 4 | # 1. Install GHCup 5 | 6 | install GHCup: `curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh` 7 | 8 | 9 | # 2. Install LLVM 10 | 11 | `arch -arm64 brew install llvm@11` 12 | `LLVM_CONFIG="/opt/homebrew/Cellar/llvm@11/11.1.0_4/bin/llvm-config" arch -arm64 pip install llvmlite` 13 | 14 | - probar `python3.10 -m pip` en vez de `pip` si no anda 15 | 16 | ## 2.1 (Optional) run hello world with llc compiler 17 | 18 | - `clang -O3 -emit-llvm hello.c -c -o hello.bc` 19 | - `llc hello.bc -o hello.s` 20 | - `gcc hello.s -o hello.native ` 21 | - `./hello` 22 | 23 | 24 | # 3. Correr Kaleidoscope (ghci) 25 | 26 | ## 3.1 ghci 27 | 28 | ``` 29 | :l Main 30 | main 31 | ``` 32 | 33 | ## 3.2 ghc 34 | 35 | ``` 36 | ghc Main 37 | ./Main 38 | ``` 39 | 40 | ## 3.3 Ejemplo del capitulo 2 41 | 42 | ``` 43 | ready> def foo(x y) x+foo(y, 4.0); 44 | Function "foo" [Var "x",Var "y"] (BinOp Plus (Var "x") (Call "foo" [Var "y",Float 4.0])) 45 | ``` 46 | 47 | # 4. Docker (wip) 48 | 49 | Se puede usar amd64 o arm64. El Dockerfile esta configurado con amd64 por ahora. 50 | 51 | - docker build -t kaleidoscope-amd64 . 52 | - docker run -it kaleidoscope-amd64 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | --------------------------------------------------------------------------------