content: {-# LANGUAGE
    TemplateHaskell,
    ForeignFunctionInterface
    #-}
  
  module LLVM.General.Internal.FFI.PassManager where
  
  import LLVM.General.Prelude
  
  import qualified Language.Haskell.TH as TH
  
  import Foreign.Ptr
  import Foreign.C
  
  import LLVM.General.Internal.FFI.LLVMCTypes
  import LLVM.General.Internal.FFI.PtrHierarchy
  import LLVM.General.Internal.FFI.Cleanup
  import LLVM.General.Internal.FFI.Module
  import LLVM.General.Internal.FFI.Target
  import LLVM.General.Internal.FFI.DataLayout
  import LLVM.General.Internal.FFI.Transforms
  
  import qualified LLVM.General.Transforms as G
  
  data PassManager
  
  foreign import ccall unsafe "LLVMCreatePassManager" createPassManager ::
    IO (Ptr PassManager)
  
  foreign import ccall unsafe "LLVMDisposePassManager" disposePassManager ::
    Ptr PassManager -> IO ()
  
  foreign import ccall unsafe "LLVMRunPassManager" runPassManager ::
    Ptr PassManager -> Ptr Module -> IO CUInt
  
  foreign import ccall unsafe "LLVMCreateFunctionPassManagerForModule" createFunctionPassManagerForModule ::
    Ptr Module -> IO (Ptr PassManager)
  
  foreign import ccall unsafe "LLVMInitializeFunctionPassManager" initializeFunctionPassManager ::
    Ptr PassManager -> IO CUInt
  
  foreign import ccall unsafe "LLVMRunFunctionPassManager" runFunctionPassManager ::
    Ptr PassManager -> Ptr Value -> IO CUInt
  
  foreign import ccall unsafe "LLVMFinalizeFunctionPassManager" finalizeFunctionPassManager ::
    Ptr PassManager -> IO CUInt
  
  foreign import ccall unsafe "LLVMAddTargetData" addDataLayoutPass' ::
    Ptr DataLayout -> Ptr PassManager -> IO ()
  
  addDataLayoutPass = flip addDataLayoutPass'
  
  foreign import ccall unsafe "LLVM_General_LLVMAddAnalysisPasses" addAnalysisPasses ::
    Ptr TargetMachine -> Ptr PassManager -> IO ()
  
  foreign import ccall unsafe "LLVMAddTargetLibraryInfo" addTargetLibraryInfoPass' ::
    Ptr TargetLibraryInfo -> Ptr PassManager -> IO ()
  
  addTargetLibraryInfoPass = flip addTargetLibraryInfoPass'
  
  $(do
    let declareForeign :: TH.Name -> [TH.Type] -> TH.DecsQ
        declareForeign hName extraParams = do
          let n = TH.nameBase hName
              passTypeMapping :: TH.Type -> TH.TypeQ
              passTypeMapping t = case t of
                TH.ConT h | h == ''Word -> [t| CUInt |]
                          | h == ''G.GCOVVersion -> [t| CString |]
                -- some of the LLVM methods for making passes use "-1" as a special value
                -- handle those here
                TH.AppT (TH.ConT mby) t' | mby == ''Maybe ->
                  case t' of
                    TH.ConT h | h == ''Bool -> [t| NothingAsMinusOne Bool |]
                              | h == ''Word -> [t| NothingAsMinusOne Word |]
                              | h == ''FilePath -> [t| NothingAsEmptyString CString |]
                    _ -> typeMapping t
                _ -> typeMapping t
          foreignDecl 
            (cName n)
            ("add" ++ n ++ "Pass")
            ([[t| Ptr PassManager |]] 
             ++ [[t| Ptr TargetMachine |] | needsTargetMachine n]
             ++ map passTypeMapping extraParams)
            (TH.tupleT 0)
  
    TH.TyConI (TH.DataD _ _ _ cons _) <- TH.reify ''G.Pass
    liftM concat $ forM cons $ \con -> case con of
      TH.RecC n l -> declareForeign n [ t | (_,_,t) <- l ]
      TH.NormalC n [] -> declareForeign n []
      TH.NormalC n _ -> error "pass descriptor constructors with fields need to be records"
   )
  
  data PassManagerBuilder
  
  foreign import ccall unsafe "LLVMPassManagerBuilderCreate" passManagerBuilderCreate ::
      IO (Ptr PassManagerBuilder) 
  
  foreign import ccall unsafe "LLVMPassManagerBuilderDispose" passManagerBuilderDispose ::
      Ptr PassManagerBuilder -> IO ()
  
  foreign import ccall unsafe "LLVMPassManagerBuilderSetOptLevel" passManagerBuilderSetOptLevel ::
      Ptr PassManagerBuilder -> CUInt -> IO () 
  
  foreign import ccall unsafe "LLVMPassManagerBuilderSetSizeLevel" passManagerBuilderSetSizeLevel ::
      Ptr PassManagerBuilder -> CUInt -> IO ()
  
  foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableUnitAtATime" passManagerBuilderSetDisableUnitAtATime ::
      Ptr PassManagerBuilder -> LLVMBool -> IO () 
  
  foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableUnrollLoops" passManagerBuilderSetDisableUnrollLoops ::
      Ptr PassManagerBuilder -> CUInt -> IO ()
  
  foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableSimplifyLibCalls" passManagerBuilderSetDisableSimplifyLibCalls ::
      Ptr PassManagerBuilder -> LLVMBool -> IO () 
  
  foreign import ccall unsafe "LLVMPassManagerBuilderUseInlinerWithThreshold" passManagerBuilderUseInlinerWithThreshold ::
      Ptr PassManagerBuilder -> CUInt -> IO ()
  
  foreign import ccall unsafe "LLVMPassManagerBuilderPopulateFunctionPassManager" passManagerBuilderPopulateFunctionPassManager ::
      Ptr PassManagerBuilder -> Ptr PassManager -> IO () 
  
  foreign import ccall unsafe "LLVMPassManagerBuilderPopulateModulePassManager" passManagerBuilderPopulateModulePassManager ::
      Ptr PassManagerBuilder -> Ptr PassManager -> IO ()
  
  foreign import ccall unsafe "LLVMPassManagerBuilderPopulateLTOPassManager" passManagerBuilderPopulateLTOPassManager ::
      Ptr PassManagerBuilder -> Ptr PassManager -> CUChar -> CUChar -> IO () 
  
  foreign import ccall unsafe "LLVM_General_PassManagerBuilderSetLibraryInfo" passManagerBuilderSetLibraryInfo ::
      Ptr PassManagerBuilder -> Ptr TargetLibraryInfo -> IO ()
  
  foreign import ccall unsafe "LLVM_General_PassManagerBuilderSetLoopVectorize" passManagerBuilderSetLoopVectorize ::
      Ptr PassManagerBuilder -> LLVMBool -> IO ()
  
  foreign import ccall unsafe "LLVM_General_PassManagerBuilderSetSuperwordLevelParallelismVectorize" passManagerBuilderSetSuperwordLevelParallelismVectorize ::
      Ptr PassManagerBuilder -> LLVMBool -> IO ()
  