-- | A supplement to 'CodeGenMonad' that wraps some additional instructions from
--   the 'LLVM.FFI.Core' module.
module Instructions (bitcast, malloc, load, store, getStructField, phi) where
import CodeGenMonad
import qualified LLVM.FFI.Core as FFI
import qualified LLVMUtils as U
import Preprocessor (Type)

bitcast :: Value -> FFI.TypeRef -> CodeGen Value
bitcast val targetType = 
    withCurrentBuilder $ \ bldPtr ->
        U.withEmptyCString $ FFI.buildBitCast bldPtr val targetType

-- FIXME: implement garbage collection
malloc :: FFI.TypeRef -> CodeGen Value
malloc typ =
    withCurrentBuilder $ \ bldPtr ->
        U.withEmptyCString $ FFI.buildMalloc bldPtr typ
        
load :: Value -> CodeGen Value
load ptr =
    withCurrentBuilder $ \ bldPtr ->
      U.withEmptyCString $ FFI.buildLoad bldPtr ptr
     
store :: Value -> Value -> CodeGen ()
store ptr val = do
    withCurrentBuilder $ \ bldPtr ->
      FFI.buildStore bldPtr val ptr
    -- I don't know what the return value of buildStore represents but we'll ignore it
    return ()

-- | Specialized use of getElementPtr instruction for accessing the nth element
--   of a struct.
getStructField :: Value -> Int -> CodeGen Value
getStructField struct ix =
    withCurrentBuilder $ \ bldPtr ->
      U.withArrayLen [constVal 0, constVal ix] $ \numIndices indices ->
        U.withEmptyCString $
          FFI.buildGEP bldPtr struct indices (fromIntegral numIndices)
    where constVal n = FFI.constInt (FFI.integerType 32) (fromIntegral n) (fromIntegral 1)
    
phi :: Type -> [(Value, BasicBlock)] -> CodeGen Value
phi typ incoming =
  withCurrentBuilder $ \ bldPtr -> do
    llvmType <- makeType typ
    inst <- U.buildEmptyPhi bldPtr llvmType
    U.addPhiIns inst incoming
    return inst