oplang-0.2.0.0: src/Language/OpLang/Optimizer.hs
module Language.OpLang.Optimizer(optimize) where
import Control.Category((>>>))
import Control.Monad.Reader(asks)
import Control.Monad.Comp(Comp)
import Data.Opts(Opts(..))
import Language.OpLang.Syntax(Program(..), Op(..))
canDoWithOffset :: Op -> Bool
canDoWithOffset (Move _) = False
canDoWithOffset (Loop _) = False
canDoWithOffset (Call _) = False
canDoWithOffset _ = True
optimizeOnce :: [Op] -> (Bool, [Op])
optimizeOnce = go False []
where
go :: Bool -> [Op] -> [Op] -> (Bool, [Op])
go changed acc ops' =
case ops' of
Add 0 : ops -> go True acc ops
Move 0 : ops -> go True acc ops
Pop 0 : ops -> go True acc ops
Loop [Add (-1)] : ops -> go True acc (Set 0 : ops)
Loop [Add 1] : ops -> go True acc (Set 0 : ops)
Set s : Add a : ops -> go True acc (Set (s + a) : ops)
Add a : Add b : ops -> go True acc (Add (a + b) : ops)
Move a : Move b : ops -> go True acc (Move (a + b) : ops)
Pop a : Pop b : ops -> go True acc (Pop (a + b) : ops)
Write a : Write b : ops -> go True acc (Write (a + b) : ops)
Add _ : ops@(Read : _) -> go True acc ops
Add _ : ops@(Pop _ : _) -> go True acc ops
Add _ : ops@(Set _ : _) -> go True acc ops
Set _ : ops@(Read : _) -> go True acc ops
Set _ : ops@(Pop _ : _) -> go True acc ops
Set _ : ops@(Set _ : _) -> go True acc ops
Pop n : Push : ops -> go True acc (Pop (n - 1) : Peek : ops)
Push : Pop n : ops -> go True acc (Pop (n - 1) : ops)
Move m : op : Move n : ops
| canDoWithOffset op && m == -n -> case op of
WithOffset o op' -> go True acc (WithOffset (m + o) op' : ops)
_ -> go True acc (WithOffset m op : ops)
Set 0 : Loop _ : ops -> go True acc (Set 0 : ops)
l@(Loop _) : Loop _ : ops -> go True acc (l : ops)
Loop [l@(Loop _)] : ops -> go True acc (l : ops)
Loop l : ops ->
let (changed', l') = go False [] l
in go changed' (Loop l' : acc) ops
op : ops -> go changed (op : acc) ops
[] -> (changed, reverse acc)
optimizeN :: Word -> [Op] -> [Op]
optimizeN 0 ops = ops
optimizeN n ops =
if changed
then optimizeN (n - 1) ops'
else ops'
where
(changed, ops') = optimizeOnce ops
removeSet0 :: [Op] -> [Op]
removeSet0 (Set 0 : ops) = ops
removeSet0 ops = ops
optimizeOps :: Word -> [Op] -> [Op]
optimizeOps passes ops = removeSet0 $ optimizeN passes (Set 0 : ops)
optimize :: Program -> Comp Program
optimize Program{..} =
asks $ optsOptPasses >>> \passes ->
Program
{ opDefs = optimizeOps passes <$> opDefs
, topLevel = optimizeOps passes topLevel
}