parsley-core-2.3.0.0: src/ghc/Parsley/Internal/Backend/Analysis/Relevancy.hs
{-# LANGUAGE MultiParamTypeClasses,
TypeFamilies,
UndecidableInstances #-}
{-|
Module : Parsley.Internal.Backend.Analysis.Relevancy
Description : Value relevancy analysis.
License : BSD-3-Clause
Maintainer : Jamie Willis
Stability : experimental
Exposes an analysis that can determine whether each of the values present on the stack for a
given machine are actually used or not. This information may be useful in the future to calculate
whether a register is "dead" or not.
@since 1.5.0.0
-}
module Parsley.Internal.Backend.Analysis.Relevancy (relevancy, Length) where
import Data.Kind (Type)
import Parsley.Internal.Backend.Machine (Instr(..), Handler(..))
import Parsley.Internal.Common.Indexed (cata4, Fix4)
import Parsley.Internal.Common.Vec (Vec(..), Nat(..), SNat(..), SingNat(..), zipWithVec, replicateVec)
{-|
Provides a conservative estimate on whether or not each of the elements of the stack on
entry to a machine are actually used in the computation.
@since 1.5.0.0
-}
relevancy :: SingNat (Length xs) => Fix4 (Instr o) xs n r a -> Vec (Length xs) Bool
relevancy = ($ sing) . getStack . cata4 (RelevancyStack . alg)
{-|
Computes the length of a type-level list. Used to index a `Vec`.
@since 1.5.0.0
-}
type family Length (xs :: [Type]) :: Nat where
Length '[] = Zero
Length (_ : xs) = Succ (Length xs)
newtype RelevancyStack xs (n :: Nat) r a = RelevancyStack { getStack :: SNat (Length xs) -> Vec (Length xs) Bool }
zipRelevancy :: Vec n Bool -> Vec n Bool -> Vec n Bool
zipRelevancy = zipWithVec (||)
-- This algorithm is over-approximating: join and ret aren't _always_ relevant
alg :: Instr o RelevancyStack xs n r a -> SNat (Length xs) -> Vec (Length xs) Bool
alg Ret _ = VCons True VNil
alg (Push _ k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg (Pop k) (SSucc n) = VCons False (getStack k n)
alg (Lift2 _ k) (SSucc n) = let VCons rel xs = getStack k n in VCons rel (VCons rel xs)
alg (Sat _ k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg (Call _ k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg Empt n = replicateVec n False
alg (Commit k) n = getStack k n
alg (Catch k _) n = getStack k n
alg (Tell k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg (Seek k) (SSucc n) = VCons True (getStack k n)
alg (Case p q) n = VCons True (let VCons _ xs = zipRelevancy (getStack p n) (getStack q n) in xs)
alg (Choices _ ks def) (SSucc n) = VCons True (foldr (zipRelevancy . (`getStack` n)) (getStack def n) ks)
alg (Iter _ _ h) n = let VCons _ xs = algHandler h (SSucc n) in xs
alg (Join _) (SSucc n) = VCons True (replicateVec n False)
alg (MkJoin _ b _) n = let VCons _ xs = getStack b (SSucc n) in xs
alg (Swap k) n = let VCons rel1 (VCons rel2 xs) = getStack k n in VCons rel2 (VCons rel1 xs)
alg (Dup k) n = let VCons rel1 (VCons rel2 xs) = getStack k (SSucc n) in VCons (rel1 || rel2) xs
alg (Make _ _ k) (SSucc n) = VCons False (getStack k n)
alg (Get _ _ k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg (Put _ _ k) (SSucc n) = VCons False (getStack k n)
alg (SelectPos _ k) n = let VCons _ xs = getStack k (SSucc n) in xs
alg (LogEnter _ k) n = getStack k n
alg (LogExit _ k) n = getStack k n
alg (MetaInstr _ k) n = getStack k n
algHandler :: Handler o RelevancyStack xs n r a -> SNat (Length xs) -> Vec (Length xs) Bool
algHandler (Same _ yes _ no) (SSucc n) = VCons True (let VCons _ xs = zipRelevancy (VCons False (getStack yes n)) (getStack no (SSucc n)) in xs)
algHandler (Always _ k) n = getStack k n