{-# LANGUAGE ForeignFunctionInterface #-}
module LLVM.Target.Native(initializeNativeTarget) where

import qualified LLVM.FFI.Core as LLVM

import Control.Concurrent.MVar (MVar, newMVar, takeMVar, putMVar)
import Control.Monad (when)

import System.IO.Unsafe (unsafePerformIO)


foreign import ccall unsafe "LLVMInitNativeTarget"
        llvmInitializeNativeTarget :: IO LLVM.Bool

-- | Initialize jitter to the native target.
-- The operation is idempotent.
initializeNativeTarget :: IO ()
initializeNativeTarget :: IO ()
initializeNativeTarget = do
    Bool
done <- MVar Bool -> IO Bool
forall a. MVar a -> IO a
takeMVar MVar Bool
refDone
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
done) (IO Bool
llvmInitializeNativeTarget IO Bool -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) -- initializeTarget
    MVar Bool -> Bool -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Bool
refDone Bool
True

-- UNSAFE: global variable to keep track of initialization state.
refDone :: MVar Bool
refDone :: MVar Bool
refDone = IO (MVar Bool) -> MVar Bool
forall a. IO a -> a
unsafePerformIO (IO (MVar Bool) -> MVar Bool) -> IO (MVar Bool) -> MVar Bool
forall a b. (a -> b) -> a -> b
$ Bool -> IO (MVar Bool)
forall a. a -> IO (MVar a)
newMVar Bool
False