Ответ 1
Типы Module
и Function
представляют собой только тонкие обертки вокруг указателей на соответствующие объекты С++ (то есть Module*
и Value*
):
-- LLVM.Core.Util
newtype Module = Module {
fromModule :: FFI.ModuleRef
}
deriving (Show, Typeable)
type Function a = Value (Ptr a)
newtype Value a = Value { unValue :: FFI.ValueRef }
deriving (Show, Typeable)
-- LLVM.FFI.Core
data Module
deriving (Typeable)
type ModuleRef = Ptr Module
data Value
deriving (Typeable)
type ValueRef = Ptr Value
Типы CodeGenModule
и CodeGenFunction
являются частями EDSL, построенных поверх модулей LLVM.FFI.*
. Они используют Function
, Module
и функции из LLVM.FFI.*
внутри и позволяют вам писать LLVM IR в Haskell в сжатом виде с использованием do-notation (пример взято из Lennart Augustsson blog):
mFib :: CodeGenModule (Function (Word32 -> IO Word32))
mFib = do
fib <- newFunction ExternalLinkage
defineFunction fib $ \ arg -> do
-- Create the two basic blocks.
recurse <- newBasicBlock
exit <- newBasicBlock
[...]
ret r
return fib
Вы можете думать о CodeGenModule
как AST, представляющем проанализированный файл сборки LLVM (.ll
). Учитывая CodeGenModule
, вы можете, например, напишите его в файл .bc
:
-- newModule :: IO Module
mod <- newModule
-- defineModule :: Module -> CodeGenModule a -> IO a
defineModule mod $ do [...]
-- writeBitcodeToFile :: FilePath -> Module -> IO ()
writeBitcodeToFile "mymodule.bc" mod
--- Alternatively, just use this function from LLVM.Util.File:
writeCodeGenModule :: FilePath -> CodeGenModule a -> IO ()
Я также рекомендую вам ознакомиться с основными классами LLVM, так как они также отображаются в API Haskell.