Add standard library tutorial-3
authorLuke Lau <luke_lau@icloud.com>
Sat, 9 Nov 2019 18:20:12 +0000 (18:20 +0000)
committerLuke Lau <luke_lau@icloud.com>
Sat, 9 Nov 2019 18:37:05 +0000 (18:37 +0000)
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

.gitignore [new file with mode: 0644]
Main.hs
Makefile [new file with mode: 0644]
stdlib.c [new file with mode: 0644]
stdlib.syms [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..38b1613
--- /dev/null
@@ -0,0 +1,3 @@
+stdlib.dylib
+stdlib.o
+Main
diff --git a/Main.hs b/Main.hs
index 97407fee2fbf6ef7907f3f45a934e737fa29d593..64d73e60e0a059864222aec09f8b2ad0803adcfd 100644 (file)
--- 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 (file)
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 (file)
index 0000000..9749ee3
--- /dev/null
+++ b/stdlib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+// 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 (file)
index 0000000..94f22f1
--- /dev/null
@@ -0,0 +1 @@
+_putchard