module Foreign.Storable.Generic.Plugin (plugin) where
import GhcPlugins
import Data.Maybe
import Foreign.Storable.Generic.Plugin.Internal
import Data.IORef
import Data.List
import Control.Monad (when)
import Foreign.Storable.Generic.Plugin.Internal.Error
plugin :: Plugin
plugin = defaultPlugin {
installCoreToDos = install
}
defFlags = Flags Some False
orderingPass :: Flags -> IORef [[Type]] -> CoreToDo
orderingPass flags io_ref = CoreDoPluginPass "GStorable - type ordering"
(groupTypes flags io_ref)
substitutionPass :: Flags -> IORef [[Type]] -> CoreToDo
substitutionPass flags io_ref = CoreDoPluginPass "GStorable - substitution"
(gstorableSubstitution flags io_ref)
isPhase0 :: CoreToDo
-> Bool
isPhase0 (CoreDoSimplify iters simpl_mode) = case sm_phase $ simpl_mode of
Phase 0 -> True
_ -> False
isPhase0 _ = False
afterPhase0 :: [CoreToDo] -> Maybe Int
afterPhase0 todos = findIndex isPhase0 todos
isSpecialize :: CoreToDo -> Bool
isSpecialize CoreDoSpecialising = True
isSpecialize _ = False
afterSpecialize :: [CoreToDo] -> Maybe Int
afterSpecialize todos = findIndex isSpecialize todos
setOpts :: Flags -> String -> Flags
setOpts (Flags _ crash) "-v0" = Flags None crash
setOpts (Flags _ crash) "-v1" = Flags Some crash
setOpts (Flags _ crash) "-v2" = Flags All crash
setOpts (Flags verb _ ) "-crash" = Flags verb True
setOpts flags opt = flags
parseOpts :: [CommandLineOption] -> Flags
parseOpts opts = foldl' setOpts defFlags opts
putPasses :: Flags -> [CoreToDo] -> Int -> Int -> CoreM [CoreToDo]
putPasses flags todos ph0 sp = do
the_ioref <- liftIO $ newIORef []
let (before_spec,after_spec) = splitAt sp todos
(before_ph0 ,after_ph0) = splitAt (ph0-sp) after_spec
ordering = orderingPass flags the_ioref
substitute = substitutionPass flags the_ioref
new_todos = concat [before_spec, [ordering], before_ph0, [substitute] , after_ph0]
return new_todos
install_err :: Flags -> CoreM ()
install_err flags = do
let (Flags verb to_crash) = flags
printer = case verb of
None -> return ()
other -> putMsg $ text "The GStorable plugin requires simplifier phases with inlining and rules on, as well as a specialiser phase."
$$ text "Try to compile the code with -O1 or -O2 optimisation flags."
printer
when to_crash $ (return $ error "Crashing...")
install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
install opts todos = do
dyn_flags <- getDynFlags
let opt_level = optLevel dyn_flags
flags = parseOpts opts
m_phase0 = afterPhase0 todos
m_spec = afterSpecialize todos
case (m_phase0, m_spec, opt_level) of
(_ ,_ ,0) -> install_err flags >> return todos
(Just ph0, Just sp,_) -> putPasses flags todos (ph0+1) (sp+1)
(_ ,_ ,_) -> install_err flags >> return todos