Set up the LLVM context and optimise the module
authorLuke Lau <luke_lau@icloud.com>
Sun, 19 May 2019 14:58:31 +0000 (15:58 +0100)
committerLuke Lau <luke_lau@icloud.com>
Thu, 7 Nov 2019 17:10:39 +0000 (17:10 +0000)
Now that we have some LLVM IR generated, we can run PassManager on our
module to get a bunch of neat optimisations on it. Try it out with 3 + 2
to see some constant folding.
Note that the original tutorial uses FunctionPassManager which optimises
on a function per function basis: llvm-hs doesn't expose this yet (and
this is all using the legacy pass manager anyway), so for now we just
optimise the entire module at the end.

Main.hs
Utils.hs

diff --git a/Main.hs b/Main.hs
index 2a5a7e0fbc6c490b0d90af2da2e54a843138341f..c3f929214099d738794ea2b6a76abe7be0d3124f 100644 (file)
--- a/Main.hs
+++ b/Main.hs
@@ -2,6 +2,7 @@
 
 import AST as K -- K for Kaleidoscope
 import Utils
+import Control.Monad.Trans.Class
 import Control.Monad.Trans.Reader
 import Control.Monad.IO.Class
 import Data.String
@@ -13,16 +14,23 @@ import LLVM.AST.Float
 import LLVM.AST.FloatingPointPredicate hiding (False, True)
 import LLVM.AST.Operand
 import LLVM.AST.Type as Type
+import LLVM.Context
 import LLVM.IRBuilder
+import LLVM.Module
+import LLVM.PassManager
 import LLVM.Pretty
+import LLVM.Target
 import System.IO
 import System.IO.Error
 import Text.Read (readMaybe)
 
 main :: IO ()
-main = buildModuleT "main" repl >>= Text.hPutStrLn stderr . ("\n" <>) . ppll
+main = do
+  withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> do
+    ast <- runReaderT (buildModuleT "main" repl) ctx
+    return ()
 
-repl :: ModuleBuilderT IO ()
+repl :: ModuleBuilderT (ReaderT Context IO) ()
 repl = do
   liftIO $ hPutStr stderr "ready> "
   mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler
@@ -34,6 +42,14 @@ repl = do
         Just ast -> do
           hoist $ buildAST ast
           mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll
+
+          ast <- moduleSoFar "main"
+          ctx <- lift ask
+          liftIO $ withModuleFromAST ctx ast $ \mdl -> do
+            let spec = defaultCuratedPassSetSpec { optLevel = Just 3 }
+            -- this returns true if the module was modified
+            withPassManager spec $ flip runPassManager mdl
+            Text.hPutStrLn stderr . ("\n" <>) . ppllvm =<< moduleAST mdl
       repl
   where
     eofHandler e
index 2a83c3591276ea116a969301fd4f24ae772af949..3bd3b37e01e54274cf4841b52e18d8d4b2cea97e 100644 (file)
--- a/Utils.hs
+++ b/Utils.hs
@@ -4,11 +4,18 @@ Shoving away gross stuff into this one module.
 module Utils where
 
 import Control.Monad.Trans.State
+import Data.ByteString.Short (ShortByteString)
 import Data.Functor.Identity
 import LLVM.AST
 import LLVM.IRBuilder.Module
 import LLVM.IRBuilder.Internal.SnocList
 
+moduleSoFar :: MonadModuleBuilder m => ShortByteString -> m Module
+moduleSoFar nm = do
+  s <- liftModuleState get
+  let ds = getSnocList (builderDefs s)
+  return $ defaultModule { moduleName = nm, moduleDefinitions = ds }
+
 mostRecentDef :: Monad m => ModuleBuilderT m Definition
 mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get