WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit 4e3377a2 authored by nathyong's avatar nathyong
Browse files

Implement variable capturing

parent 70a4766e
Pipeline #5 failed with stage
in 4 minutes and 45 seconds
...@@ -16,8 +16,9 @@ cabal-version: >=1.10 ...@@ -16,8 +16,9 @@ cabal-version: >=1.10
library library
hs-source-dirs: src hs-source-dirs: src
other-extensions: other-extensions:
TemplateHaskell, GeneralizedNewtypeDeriving,
GeneralizedNewtypeDeriving OverloadedStrings,
DeriveGeneric
ghc-options: -Wall ghc-options: -Wall
exposed-modules: Compiler.Mu exposed-modules: Compiler.Mu
, Compiler.Mu.CodeGen , Compiler.Mu.CodeGen
...@@ -48,7 +49,6 @@ executable anuhc-exe ...@@ -48,7 +49,6 @@ executable anuhc-exe
, mu , mu
, mu-pure , mu-pure
, containers , containers
, directory
, ghc-simple , ghc-simple
, text , text
default-language: Haskell2010 default-language: Haskell2010
......
...@@ -43,14 +43,14 @@ compilerConfig = ...@@ -43,14 +43,14 @@ compilerConfig =
{ cfgUseGhcErrorLogger = True { cfgUseGhcErrorLogger = True
, cfgStopPhases = GHC.Simple.ncgPhases , cfgStopPhases = GHC.Simple.ncgPhases
, cfgGhcFlags = ["-ddump-stg", "-ddump-cmm-raw", "-ddump-to-file"] {-"-v5",-} , cfgGhcFlags = ["-ddump-stg", "-ddump-cmm-raw", "-ddump-to-file"] {-"-v5",-}
, cfgCacheDirectory = Just "/tmp/" , cfgCacheDirectory = Just "/tmp/anuhc/"
} }
main :: IO () main :: IO ()
main = do main = do
inputFiles <- getArgs inputFiles <- getArgs
b <- GHC.Simple.compileWith compilerConfig compileMu inputFiles b <- GHC.Simple.compileWith compilerConfig compileMu inputFiles
libresults <- mapM compileLibraryFiles libraryFiles libresults <- return [] -- mapM compileLibraryFiles libraryFiles
case b of case b of
Success results _ _ -> do Success results _ _ -> do
doResults lives $ mergeResults $ (loadPrim : concat libresults ++ results') doResults lives $ mergeResults $ (loadPrim : concat libresults ++ results')
...@@ -60,8 +60,8 @@ main = do ...@@ -60,8 +60,8 @@ main = do
getDefns (defns, _, _) = fmap toName defns getDefns (defns, _, _) = fmap toName defns
Failure _ _ -> exitFailure Failure _ _ -> exitFailure
compileLibraryFiles :: (String, [FilePath]) -> IO [MuResult] compileLibraryFiles :: (String, [FilePath], [String]) -> IO [MuResult]
compileLibraryFiles (packageKey, files) = do compileLibraryFiles (packageKey, files, extraFlags) = do
traceM ("Compiling the library file " ++ packageKey) traceM ("Compiling the library file " ++ packageKey)
b <- GHC.Simple.compileWith libconfig compileMu files b <- GHC.Simple.compileWith libconfig compileMu files
case b of case b of
...@@ -70,7 +70,9 @@ compileLibraryFiles (packageKey, files) = do ...@@ -70,7 +70,9 @@ compileLibraryFiles (packageKey, files) = do
where where
libconfig = compilerConfig libconfig = compilerConfig
{ cfgGhcFlags = { cfgGhcFlags =
["-this-unit-id", packageKey, "-ddump-stg", "-ddump-to-file"] [ "-this-unit-id", packageKey, "-ddump-stg", "-ddump-to-file"
, "-I/Users/nathan/projects/microvm/anuhc/libraries/include/"]
++ extraFlags
} }
doResults :: [Name] -> MuMergedResult -> IO () doResults :: [Name] -> MuMergedResult -> IO ()
...@@ -97,9 +99,9 @@ doResults liveObjectNames (defns, topClosures, mainFunction) = do ...@@ -97,9 +99,9 @@ doResults liveObjectNames (defns, topClosures, mainFunction) = do
-- | A list of all library files, indexed by their package-key. -- | A list of all library files, indexed by their package-key.
-- TODO: fix this. -- TODO: fix this.
libraryFiles :: [(String, [FilePath])] libraryFiles :: [(String, [FilePath], [String])]
libraryFiles = [ ("ghc-prim", prefix ghcPrimFiles) libraryFiles = [ ("ghc-prim", prefix ghcPrimFiles, [])
, ("base", prefix baseFiles) , ("base", prefix baseFiles, ["-I/Users/nathan/projects/microvm/anuhc/libraries/base/include/", "-i/Users/nathan/projects/microvm/anuhc/libraries/base"])
] ]
where where
prefix = fmap ("/Users/nathan/projects/microvm/anuhc/libraries/" ++) prefix = fmap ("/Users/nathan/projects/microvm/anuhc/libraries/" ++)
......
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
-- Utility functions for Haskell code generation via Mu. -- Utility functions for Haskell code generation via Mu.
-- --
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
module Compiler.Mu.CodeGen module Compiler.Mu.CodeGen
( -- * Mu Monad ( -- * Mu Monad
...@@ -21,17 +21,26 @@ module Compiler.Mu.CodeGen ...@@ -21,17 +21,26 @@ module Compiler.Mu.CodeGen
, runMu , runMu
, definitions , definitions
, topLevels , topLevels
, currentBlock
, MuResult , MuResult
, MuMergedResult , MuMergedResult
, mergeResults , mergeResults
-- * Block building monad -- * Block building monad
, Blocks , Blocks
, CapturedIDs
, sortedIDs
, sortedIDNames
, BasicBlocks
, ExpWriter
, runBlocks , runBlocks
, capturing
, lookupID
, basicBlock , basicBlock
, paramsFor
, assign , assign
, emit , emit
, emitBB
, upTag , upTag
, upConstant
, upValue , upValue
-- * Code generation -- * Code generation
, UnboxedData (..) , UnboxedData (..)
...@@ -66,12 +75,15 @@ module Compiler.Mu.CodeGen ...@@ -66,12 +75,15 @@ module Compiler.Mu.CodeGen
, getClosureField , getClosureField
, getClosureData , getClosureData
, ClosureField (..) , ClosureField (..)
-- * Utility functions
, isInternal
) where ) where
import Control.Monad.Trans (MonadTrans, lift)
import Control.Applicative ((<|>)) import Control.Applicative ((<|>))
import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.State (State, StateT, MonadState, evalState, runStateT, gets) import Control.Monad.Reader (Reader, ReaderT, MonadReader, runReaderT, ask, local, reader)
import Control.Monad.State.Strict (State, StateT, MonadState, evalState, runStateT, gets)
import Control.Monad.Trans (MonadTrans, lift)
import Control.Monad.Writer (Writer, WriterT, MonadWriter, runWriterT, tell) import Control.Monad.Writer (Writer, WriterT, MonadWriter, runWriterT, tell)
import Data.Binary (Binary) import Data.Binary (Binary)
import Data.Foldable (toList, foldl') import Data.Foldable (toList, foldl')
...@@ -82,11 +94,13 @@ import Data.Sequence (Seq, (|>)) ...@@ -82,11 +94,13 @@ import Data.Sequence (Seq, (|>))
import Data.String (fromString) import Data.String (fromString)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.Sequence as S
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
import qualified Foreign as F import qualified Foreign as F
import qualified Foreign.C as C import qualified Foreign.C as C
import Lens.Micro.Platform ((%=), makeLenses) import Language.Haskell.GHC.Simple (ModMetadata(..), mmSummary)
import Lens.Micro.Platform ((%=), Lens')
import FastString (fsLit, zEncodeFS, zString) import FastString (fsLit, zEncodeFS, zString)
import qualified GHC import qualified GHC
...@@ -117,6 +131,7 @@ instance HasName TopLevel where ...@@ -117,6 +131,7 @@ instance HasName TopLevel where
data UnboxedData = UnboxedInt Integer data UnboxedData = UnboxedInt Integer
| UnboxedDouble Rational | UnboxedDouble Rational
| TaggedPointer GlobalCellName Int | TaggedPointer GlobalCellName Int
| NullPointer
deriving (Generic) deriving (Generic)
instance Binary UnboxedData instance Binary UnboxedData
...@@ -143,81 +158,160 @@ newtype Mu a = Mu (State MuState a) ...@@ -143,81 +158,160 @@ newtype Mu a = Mu (State MuState a)
deriving (Functor, Applicative, Monad, MonadState MuState) deriving (Functor, Applicative, Monad, MonadState MuState)
-- | Run a Mu computation from the empty state, storing the result. -- | Run a Mu computation from the empty state, storing the result.
runMu :: Mu a -> a runMu :: MuState -> Mu a -> a
runMu (Mu code) = evalState code $ MuState 0 mempty mempty () runMu state (Mu code) = evalState code state
data MuState = MuState data MuState = MuState
{ _uniqueID :: !Int { _uniqueID :: !Int
, _moduleName :: String
, _definitions :: Seq Definition , _definitions :: Seq Definition
, _topLevels :: Seq TopLevel , _topLevels :: Seq TopLevel
, _currentBlock :: ()
} }
makeLenses ''MuState uniqueID :: Lens' MuState Int
uniqueID k m = fmap (\new -> m { _uniqueID = new }) (k (_uniqueID m))
moduleName :: Lens' MuState String
moduleName k m = fmap (\new -> m { _moduleName = new }) (k (_moduleName m))
definitions :: Lens' MuState (Seq Definition)
definitions k m = fmap (\new -> m { _definitions = new }) (k (_definitions m))
topLevels :: Lens' MuState (Seq TopLevel)
topLevels k m = fmap (\new -> m { _topLevels = new }) (k (_topLevels m))
-------------------------------------------------- * Block building monad -------------------------------------------------- * Block building monad
data BlockState = BlockState { _blocks :: Seq BasicBlock } -- | Read only state for building blocks.
type CapturedIDs = Map GHC.Id VarName
sortedIDs :: CapturedIDs -> [GHC.Id]
sortedIDs mapping = fmap fst $ M.toAscList mapping
-- | Mutable state for the block building monad
type BasicBlocks = Seq BasicBlock
makeLenses ''BlockState -- | An environment for outputing individual instructions.
type ExpWriter = WriterT [Assigned Expression] Blocks
newtype Blocks a = Blocks (StateT BlockState Mu a)
deriving (Functor, Applicative, Monad, MonadState BlockState)
type BlocksWriter = WriterT [Assigned Expression] Blocks -- | A monad for all of the state involved when building a function. This
-- includes the basic blocks and their instructions, as well as the captured
-- variables inside a particular function.
newtype Blocks a = Blocks (ReaderT CapturedIDs (WriterT BasicBlocks Mu) a)
deriving (Functor, Applicative, Monad, MonadWriter BasicBlocks, MonadReader CapturedIDs)
runBlocks :: Blocks a -> Mu (a, Seq BasicBlock) runBlocks :: CapturedIDs -> Blocks a -> Mu (a, BasicBlocks)
runBlocks (Blocks code) = do runBlocks r (Blocks code) = do
(a, bstate) <- runStateT code $ BlockState mempty (a, bbs) <- runWriterT (runReaderT code r)
return (a, _blocks bstate) traceShowM $ ("There are ", S.length bbs, " basic blocks")
return (a, bbs)
-- | Lift a 'Mu' computation into the Blocks monad. -- | Run a 'Blocks' computation inside a local environment capturing extra
-- variables.
capturing :: MonadReader CapturedIDs m
=> m a -- ^ Computation to run
-> Map GHC.Id VarName -- ^ Extra variables to capture
-> m a
capturing b r = local (M.union r) b
sortedIDNames :: MonadReader CapturedIDs m => m [VarName]
sortedIDNames = ask >>= return . fmap snd . M.toAscList
-- | Obtain the 'VarName' for a particular 'GHC.Id' in the current mapping. If
-- it does not exist, crash and burn spectacularly.
lookupID :: GHC.Id -> ExpWriter VarName
lookupID i = lift $ do
n <- reader (M.lookup i)
case n of
Nothing -> error ("lookupID: could not find " ++ stringify i)
Just n' -> return n'
-- | Lift a 'Mu' computation into the 'Blocks' monad.
liftBlocks :: Mu a -> Blocks a liftBlocks :: Mu a -> Blocks a
liftBlocks m = Blocks (lift m) liftBlocks m = Blocks (lift . lift $ m)
-- | Emit a basic block without an exceptional parameter. -- | Emit a basic block without an exceptional parameter.
basicBlock basicBlock
:: BasicBlockName :: BasicBlockName -- ^ Name of the block itself
-> [(VarName, TypedefName)] -> [(VarName, TypedefName)] -- ^ Parameters of the block, and their types
-> BlocksWriter Expression -> ExpWriter Expression -- ^ Code to generate expressions within the block
-> Blocks BasicBlock -> Blocks BasicBlock
basicBlock n params exprs = do basicBlock n params exprs = do
(terminator, body) <- runWriterT exprs bindings <- ask
return $ BasicBlock n params Nothing body terminator (terminator, body) <- runWriterT exprs `capturing` newMappings n bindings
return $ BasicBlock n (params ++ paramsFor n bindings) Nothing body terminator
-- | Generate a new mapping for
newMappings :: BasicBlockName
-> Map GHC.Id a
-> CapturedIDs
newMappings block mapping = M.mapWithKey genParam mapping
where
genParam i _ = block `dot` tail (stringify i)
-- | Obtain a list of variables and their types
paramsFor :: BasicBlockName
-> Map GHC.Id a
-> [(VarName, TypedefName)]
paramsFor block mapping = fmap pairUp (M.toAscList mapping)
where where
pairUp (i, _) = (block `dot` tail (stringify i), haskellData)
-- | Assign the result of a Mu 'Expression' to a 'VarName'. -- | Assign the result of a Mu 'Expression' to a 'VarName'.
assign :: Expression -> BlocksWriter VarName assign :: Expression -> ExpWriter VarName
assign expr = do assign expr = do
uid <- lift $ liftBlocks nextMuUnique uid <- lift $ liftBlocks nextMuUnique
let n = fromString ("@var" ++ show uid) let n = fromString ("@var" ++ uid)
tell $ [[n] := expr] emit' $ [n] := expr
return n return n
-- | Run a Mu 'Expression' without binding to anything. -- | Run a Mu 'Expression' without binding to anything.
emit :: Expression -> BlocksWriter () emit :: Expression -> ExpWriter ()
emit expr = tell $ [[] := expr] emit expr = emit' $ [] := expr
emit' :: Assigned Expression -> ExpWriter ()
emit' = tell . pure
emitBB :: BasicBlock -> Blocks ()
emitBB = tell . pure
-- | Declare a (constant) tag to be defined at the top level, without -- | Declare a (constant) tag to be defined at the top level, without
-- clobbering any other upvalues. -- clobbering any other upvalues.
upTag :: Int -> BlocksWriter VarName upTag :: Int -> ExpWriter VarName
upTag i = lift . liftBlocks $ do upTag i = lift . liftBlocks $ do
let n = fromString ("@tag_const_" ++ show i) let n = fromString ("@tag_const_" ++ show i)
constant n muClosureTag (IntCtor (fromIntegral i)) constant n muClosureTag (IntCtor (fromIntegral i))
return (VarName $ toName n) return (VarName $ toName n)
-- | Declare an integer constant to be defined at the top level, without
-- clobbering any other upvalues.
upConstant :: Int -> ExpWriter VarName
upConstant i = lift . liftBlocks $ do
let n = fromString ("@i64_" ++ show i)
constant n i64 (IntCtor (fromIntegral i))
return (VarName $ toName n)
-- | Declare a (constant) value to be defined at the top level. -- | Declare a (constant) value to be defined at the top level.
upValue :: ConstConstructor -> TypedefName -> BlocksWriter VarName upValue :: ConstConstructor -> TypedefName -> ExpWriter VarName
upValue ctor ty = lift . liftBlocks $ do upValue ctor ty = lift . liftBlocks $ do
uid <- nextMuUnique uid <- nextMuUnique
let n = fromString ("@upvar" ++ show uid) let n = fromString ("@upvar" ++ uid)
constant n ty ctor constant n ty ctor
return (VarName $ toName n) return (VarName $ toName n)
...@@ -225,12 +319,14 @@ upValue ctor ty = lift . liftBlocks $ do ...@@ -225,12 +319,14 @@ upValue ctor ty = lift . liftBlocks $ do
-------------------------------------------------- * Code generation -------------------------------------------------- * Code generation
-- | Extract the definitions and other useful things from the Mu monad. -- | Extract the definitions and other useful things from the Mu monad.
bundleMu :: Mu () -> MuResult bundleMu :: String -> Mu () -> MuResult
bundleMu codegen = runMu $ do bundleMu modName codegen = runMu initialState $ do
codegen codegen
defns <- gets _definitions defns <- gets _definitions
tops <- gets _topLevels tops <- gets _topLevels
return (defns, tops, Nothing) return (defns, tops, Nothing)
where
initialState = MuState 0 modName mempty mempty
-- | Populate a Mu Closure, or other top-level data type, at build-time. -- | Populate a Mu Closure, or other top-level data type, at build-time.
...@@ -277,6 +373,13 @@ populate ctx top = case top of ...@@ -277,6 +373,13 @@ populate ctx top = case top of
cellRef <- ctxLoad ctx muOrdNotAtomic cellHandle cellRef <- ctxLoad ctx muOrdNotAtomic cellHandle
trCellRef <- tr64FromRef ctx cellRef tag' trCellRef <- tr64FromRef ctx cellRef tag'
store ctx muOrdNotAtomic ref trCellRef store ctx muOrdNotAtomic ref trCellRef
NullPointer -> do
tag' <- handleFromSint64 ctx 0 6
reftyID <- getID ctx muClosureRef
nullRef <- handleFromPtr ctx reftyID F.nullPtr
trNull <- tr64FromRef ctx nullRef tag'
store ctx muOrdNotAtomic ref trNull
shiftIref ctx ref one >>= storePayloads ds shiftIref ctx ref one >>= storePayloads ds
storePayloads payload closureDataRef storePayloads payload closureDataRef
...@@ -304,12 +407,13 @@ populate ctx top = case top of ...@@ -304,12 +407,13 @@ populate ctx top = case top of
-------------------------------------------------- * Mu interface -------------------------------------------------- * Mu interface
-- | Get a unique number from the Mu monad. -- | Get a unique identifier (name) from the Mu monad.
nextMuUnique :: Mu Int nextMuUnique :: Mu String
nextMuUnique = do nextMuUnique = do
currentID <- gets _uniqueID currentID <- gets _uniqueID
modName <- gets _moduleName
uniqueID %= (+1) uniqueID %= (+1)
return currentID return $ "_uq_" <> modName <> "_" <> show currentID
-- | Emit a closure with a payload and an entry function. The closure itself -- | Emit a closure with a payload and an entry function. The closure itself
-- will be allocated during build time. -- will be allocated during build time.
...@@ -328,7 +432,7 @@ string :: GHC.Id -> B.ByteString -> Mu GlobalCellName ...@@ -328,7 +432,7 @@ string :: GHC.Id -> B.ByteString -> Mu GlobalCellName
string name bytes = do string name bytes = do
name' <- do name' <- do
uid <- nextMuUnique uid <- nextMuUnique
return $ fromString $ stringify name <> "_str" <> show uid return $ fromString $ stringify name <> uid <> "_str"
definitions %= (|> GlobalCell name' muStringRef) definitions %= (|> GlobalCell name' muStringRef)
topLevels %= (|> ByteArray name' bytes) topLevels %= (|> ByteArray name' bytes)
return name' return name'
...@@ -352,10 +456,57 @@ funcsig n argtys rettys = definitions %= (|> SignatureDefinition n argtys rettys ...@@ -352,10 +456,57 @@ funcsig n argtys rettys = definitions %= (|> SignatureDefinition n argtys rettys
-- | Emit a function (version) definition. -- | Emit a function (version) definition.
funcdef :: FunctionName -> Version -> SignatureName -> Blocks BasicBlock -> Mu () funcdef :: FunctionName -> Version -> SignatureName -> Blocks BasicBlock -> Mu ()
funcdef n v sig body = do funcdef n v sig body = do
(entry, bblocks) <- runBlocks body (entry, bblocks) <- runBlocks M.empty body
traceBB entry
mapM_ traceBB bblocks
definitions %= (|> FunctionDefinition n v sig entry (toList bblocks)) definitions %= (|> FunctionDefinition n v sig entry (toList bblocks))
traceBB :: Applicative m => BasicBlock -> m ()
traceBB bb@(BasicBlock n ps exc insts term) = traceShowM (n, fmap sexp' insts, sexp term)
where
sexp' :: Assigned Expression -> String
sexp' (d := aexp) = show d ++ " := " ++ sexp aexp
sexp :: Expression -> String
sexp aexp = case aexp of
BinaryOperation {} -> "BinaryOperation"
CompareOperation {} -> "CompareOperation"
ConvertOperation {} -> "ConvertOperation"
AtomicRMWOperation {} -> "AtomicRMWOperation"
CmpXchg {} -> "CmpXchg"
Fence {} -> "Fence"
New {} -> "New"
NewHybrid {} -> "NewHybrid"
Alloca {} -> "Alloca"
AllocaHybrid {} -> "AllocaHybrid"
Return {} -> "Return"
Throw {} -> "Throw"
Call {} -> "Call"
CCall {} -> "CCall"
TailCall {} -> "TailCall"
Branch1 {} -> "Branch1"
Branch2 {} -> "Branch2"
WatchPoint {} -> "WatchPoint"
Trap {} -> "Trap"
WPBranch {} -> "WPBranch"
Switch {} -> "Switch"
SwapStack {} -> "SwapStack"
NewThread {} -> "NewThread"
Comminst {} -> "Comminst"
Load {} -> "Load"
Store {} -> "Store"
ExtractValue {} -> "ExtractValue"
InsertValue {} -> "InsertValue"
ExtractElement {} -> "ExtractElement"
InsertElement {} -> "InsertElement"
ShuffleVector {} -> "ShuffleVector"
GetIRef {} -> "GetIRef"
GetFieldIRef {} -> "GetFieldIRef"
GetElemIRef {} -> "GetElemIRef"
ShiftIRef {} -> "ShiftIRef"
GetVarPartIRef {} -> "GetVarPartIRef"
primfuncdef :: FunctionName -> Blocks BasicBlock -> Mu () primfuncdef :: FunctionName -> Blocks BasicBlock -> Mu ()
primfuncdef n body = funcdef n (Version "1") muClosureFunctionSig body primfuncdef n body = funcdef n (Version "1") muClosureFunctionSig body
...@@ -364,7 +515,8 @@ primfuncdef n body = funcdef n (Version "1") muClosureFunctionSig body ...@@ -364,7 +515,8 @@ primfuncdef n body = funcdef n (Version "1") muClosureFunctionSig body
stringify :: (Uniquable a, NamedThing a) => a -> String stringify :: (Uniquable a, NamedThing a) => a -> String
stringify a stringify a
| isSystemName name = '@':(stableName name <> "_" <> uniquePart a) | isSystemName name || isInternalName name =
'@':(stableName name <> "_" <> uniquePart a)
| otherwise = '@':(stableName name) | otherwise = '@':(stableName name)
where where
name = getName a name = getName a
...@@ -459,3 +611,9 @@ data ClosureField = EntryField ...@@ -459,3 +611,9 @@ data ClosureField = EntryField
fieldIx :: ClosureField -> C.CInt fieldIx :: ClosureField -> C.CInt
fieldIx = fromIntegral . fromEnum fieldIx = fromIntegral . fromEnum
-------------------------------------------------- * Utility functions