From: Luke Lau Date: Sat, 9 Nov 2019 18:20:12 +0000 (+0000) Subject: Add standard library X-Git-Url: https://git.lukelau.me/?a=commitdiff_plain;h=58bc647a182a51f277577aa7c46381a2138a2e06;hp=705b0b8458673edb7273e6e19914390a55e51d23;p=kaleidoscope-hs.git Add standard library We want to be able to call a function inside our for loop that has some sort of side effect that we can observe: How about printing to stdout? Our language isn't quite sophisticated enough yet to handle writing to files and handles or make system calls, but we can work around this by writing this code in another language and calling it from Kaleidoscope. In this chapter we are going to write our standard library in C, but feel free to experiment with compiling and linking other languages: Try making raw system calls in assembly, or even writing it in Haskell! The standard library contains one function, putchard, which takes in a double and prints a character to stdout. It's the equivalent of putchar(3), but since Kaleidoscope only works with doubles we need to cast it first. Once you have finished this chapter, you should now be able to run the following code to print out a bunch of characters: ready> extern putchard(x) declare external ccc double @putchard(double) ready> for i = 0, i < 10 in putchard(42+i) define external ccc double @__anon_expr() { preheader_0: %initcond_0 = fcmp olt double 0.000000e0, 1.000000e1 %initcond_1 = uitofp i1 %initcond_0 to double %initcond_2 = fcmp one double 0.000000e0, %initcond_1 br i1 %initcond_2, label %loop_0, label %after_0 loop_0: %i_0 = phi double [0.000000e0, %preheader_0], [%nextvar_0, %loop_0] %body_0 = fadd double 4.200000e1, %i_0 %body_1 = call ccc double @putchard(double %body_0) %nextvar_0 = fadd double %i_0, 1.000000e0 %cond_0 = fcmp olt double %i_0, 1.000000e1 %cond_1 = uitofp i1 %cond_0 to double %cond_2 = fcmp one double 0.000000e0, %cond_1 br i1 %cond_2, label %loop_0, label %after_0 after_0: ret double 0.000000e0 } Resolving MangledSymbol "_putchard" to 0x10574c2d0 *+,-./01234 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38b1613 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +stdlib.dylib +stdlib.o +Main diff --git a/Main.hs b/Main.hs index 97407fe..64d73e6 100644 --- a/Main.hs +++ b/Main.hs @@ -19,12 +19,14 @@ import LLVM.AST.Operand import LLVM.AST.Type as Type import LLVM.Context import LLVM.IRBuilder +import LLVM.Linking import LLVM.Module import LLVM.OrcJIT import LLVM.OrcJIT.CompileLayer import LLVM.PassManager import LLVM.Pretty import LLVM.Target +import Numeric import System.IO import System.IO.Error import Text.Read (readMaybe) @@ -38,7 +40,8 @@ data JITEnv = JITEnv } main :: IO () -main = +main = do + loadLibraryPermanently (Just "stdlib.dylib") withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> withExecutionSession $ \exSession -> withSymbolResolver exSession (SymbolResolver symResolver) $ \symResolverPtr -> @@ -51,7 +54,10 @@ main = -- This can eventually be used to resolve external functions, e.g. a stdlib call symResolver :: MangledSymbol -> IO (Either JITSymbolError JITSymbol) -symResolver sym = undefined +symResolver sym = do + ptr <- getSymbolAddressInProcess sym + putStrLn $ "Resolving " <> show sym <> " to 0x" <> showHex ptr "" + return (Right (JITSymbol ptr defaultJITSymbolFlags)) repl :: ModuleBuilderT (ReaderT JITEnv IO) () repl = do diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a37353 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +stdlib.dylib: stdlib.c + clang -shared $< -o $@ + +# for statically linking the stdlib: +# make sure to change in Main.hs +# loadLibraryPermanently (Just "stdlib.dylib") +# to +# loadLibraryPermanently Nothing +stdlib.o: stdlib.c + clang -c $< -o $@ + +Main: Main.hs stdlib.o + ghc $^ -o $@ -optl -Wl,-exported_symbols_list,stdlib.syms \ + -no-keep-hi-files -no-keep-o-files diff --git a/stdlib.c b/stdlib.c new file mode 100644 index 0000000..9749ee3 --- /dev/null +++ b/stdlib.c @@ -0,0 +1,7 @@ +#include +// Takes a double and writes it to stdout +double putchard(double x) { + int res = putchar((int)x); + fflush(stdout); + return (double)res; +} diff --git a/stdlib.syms b/stdlib.syms new file mode 100644 index 0000000..94f22f1 --- /dev/null +++ b/stdlib.syms @@ -0,0 +1 @@ +_putchard