-- | Do very simple peephole optimisations, mostly to do with slides and pops
module ByteCode.Peep(bcPeep) where
import ByteCode.Type
import ByteCode.Metric
-- | Simple peephole optimizer
bcPeep :: BCModule -> BCModule
bcPeep m = m { bcmDecls = map peepDecl $ bcmDecls m }
peepDecl :: BCDecl -> BCDecl
peepDecl (Fun n p z as cs cn pr sk nd fl) = Fun n p z as (peepCode cs) cn pr sk nd fl
peepDecl x = x
peepCode :: Code -> Code
peepCode (CLinear is) = CLinear is'
where
(cs,us) = unzip is
cs' = peepIns cs
is' = map (\i -> (i,emptyUS)) cs'
peepIns :: [Ins] -> [Ins]
-- merge need heaps
peepIns (NEED_HEAP 0:is) = peepIns is
peepIns (NEED_HEAP n:NEED_HEAP m:is) = peepIns (NEED_HEAP (n+m):is)
peepIns (NEED_HEAP n:NEED_STACK m:is) = peepIns (NEED_HEAP n:is)
-- we're in trouble if a needheap hits a label since a NEED_HEAP's are introduced based on a linear
-- block, and they are not introduced if nothing allocates heap. We therefore shouldn't push past something
-- that allocates heap.
peepIns (NEED_HEAP n:LABEL j:is) = error "peepIns: NEED_HEAP should never reach a label!"
-- remove needheaps infront of RETURN/RETURN_EVAL/EVAL
peepIns (NEED_HEAP n:RETURN:is) = peepIns (RETURN:is)
peepIns (NEED_HEAP n:RETURN_EVAL:is) = peepIns (RETURN_EVAL:is)
peepIns (NEED_HEAP n:EVAL:is) = peepIns (EVAL:is)
-- push back needheaps until they are needed (allows further optimisations)
peepIns (NEED_HEAP n:i:is) | usesNoHeap i = i : peepIns (NEED_HEAP n:is)
-- remove redundant slides, and merge multiple slides
peepIns (SLIDE 0:is) = peepIns is
peepIns (SLIDE n:SLIDE m:is) = peepIns (SLIDE (n+m):is)
peepIns (SLIDE n:RETURN:is) = peepIns (RETURN:is)
peepIns (SLIDE n:RETURN_EVAL:is) = peepIns (RETURN_EVAL:is)
-- remove redundant pops, and merge multiple pops
peepIns (POP 0:is) = peepIns is
peepIns (POP n:POP m:is) = peepIns (POP (n+m):is)
peepIns (POP n:RETURN:is) = peepIns (RETURN:is)
peepIns (POP n:RETURN_EVAL:is) = peepIns (RETURN_EVAL:is)
-- remove redundant evals
peepIns (EVAL:RETURN:is) = peepIns (RETURN_EVAL:is)
peepIns (EVAL:RETURN_EVAL:is) = peepIns (RETURN_EVAL:is)
peepIns (EVAL:EVAL:is) = peepIns (EVAL:is)
peepIns (i:is) = i : peepIns is
peepIns [] = []
-- | returns whether the instruction returns no heap, ignores extra since
-- no instruction should allocate extra only ...
usesNoHeap :: Ins -> Bool
usesNoHeap i = case imHeap $ bcodeMetric i of
HeapStatic f -> f 0 == 0
HeapDynamic -> False
|