This commit is contained in:
@@ -121,6 +121,7 @@ library
|
|||||||
, typed-process
|
, typed-process
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, vector
|
, vector
|
||||||
|
, tardis
|
||||||
|
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: GHC2024
|
default-language: GHC2024
|
||||||
|
|||||||
@@ -1,6 +1,103 @@
|
|||||||
module Gyehoek.CPS.Contify
|
module Gyehoek.CPS.Contify
|
||||||
(
|
( contifyProgram
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.Tardis
|
||||||
|
import Gyehoek.CPS.Syntax
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude
|
||||||
|
import qualified Data.HashSet as HS
|
||||||
|
import Control.Lens.Unsound (adjoin)
|
||||||
|
|
||||||
|
|
||||||
|
-- | ain't no way...
|
||||||
|
type T es = TardisT (HashSet Name) (HashSet Name) (Eff es)
|
||||||
|
|
||||||
|
runT :: T es a -> Eff es a
|
||||||
|
runT = (`evalTardisT` (mempty,mempty))
|
||||||
|
|
||||||
|
-- | inline function if it hasn't been used in the past, and won't
|
||||||
|
-- be used in the future.
|
||||||
|
tryInline :: Name -> Kappa -> T es Kexp
|
||||||
|
tryInline kname kap = do
|
||||||
|
modifyBackwards (HS.insert kname)
|
||||||
|
p <- getsPast (HS.member kname)
|
||||||
|
modifyForwards (HS.insert kname)
|
||||||
|
q <- getsFuture (HS.member kname)
|
||||||
|
pure $ if p || q
|
||||||
|
then KexpVar kname
|
||||||
|
else KexpKappa kap
|
||||||
|
|
||||||
|
getKap :: HashMap Name Abs -> Name -> Maybe Kappa
|
||||||
|
getKap g kname = g ^? ix kname . #AbsKappa
|
||||||
|
|
||||||
|
contify :: HashMap Name Abs -> Exp -> T es Exp
|
||||||
|
contify g = \case
|
||||||
|
ExpApply f xs (KexpVar kname) | Just kap <- getKap g kname
|
||||||
|
-> ExpApply f xs <$> tryInline kname kap
|
||||||
|
ExpPrim p (KexpVar kname) | Just kap <- getKap g kname
|
||||||
|
-> ExpPrim p <$> tryInline kname kap
|
||||||
|
e -> pure e
|
||||||
|
|
||||||
|
contifyProgram :: HoistedProgram -> Eff es HoistedProgram
|
||||||
|
contifyProgram p = do
|
||||||
|
let g = p.bindings
|
||||||
|
runT $
|
||||||
|
traverseOf
|
||||||
|
(adjoin
|
||||||
|
(#bindings . each . body)
|
||||||
|
(#body . body))
|
||||||
|
(contify g)
|
||||||
|
p
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type BidirectionalState = Tardis (HashSet Text) (HashSet Text)
|
||||||
|
|
||||||
|
runBidirectionalState = (`evalTardis` (mempty,mempty))
|
||||||
|
|
||||||
|
markAsUsed :: Hashable a => a -> HashSet a -> HashSet a
|
||||||
|
markAsUsed = HS.insert
|
||||||
|
|
||||||
|
isMarkedAsUsed :: Hashable a => a -> HashSet a -> Bool
|
||||||
|
isMarkedAsUsed = HS.member
|
||||||
|
|
||||||
|
-- | our bidirectional state monad. updates can be sent forwards or
|
||||||
|
-- backwards.
|
||||||
|
runBidirectionalState :: BidirectionalState a -> a
|
||||||
|
|
||||||
|
data InlineResult
|
||||||
|
-- | represents the successful inlining of a function.
|
||||||
|
= Inlined Text
|
||||||
|
-- | represents a function that couldn't be inlined.
|
||||||
|
| NotInlined Text
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
|
||||||
|
-- | try inlining two functions, `x` and `y`. each is used exactly
|
||||||
|
-- once, so both should be successfully inlined.
|
||||||
|
--
|
||||||
|
-- >>> runBidirectionalState example1
|
||||||
|
-- ( Inlined "x"
|
||||||
|
-- , Inlined "y"
|
||||||
|
-- )
|
||||||
|
example1 :: BidirectionalState (InlineResult, InlineResult)
|
||||||
|
example1 = do
|
||||||
|
x <- tryInline "x"
|
||||||
|
y <- tryInline "y"
|
||||||
|
pure (x,y)
|
||||||
|
|
||||||
|
-- | try inlining two functions, `x` and `y`. `x` is used twice, so
|
||||||
|
-- can't be inlined. but `y` is used once, and thus ought to be
|
||||||
|
-- inlined.
|
||||||
|
--
|
||||||
|
-- >>> runBidirectionalState example2
|
||||||
|
-- ( NotInlined "x"
|
||||||
|
-- , Inlined "y"
|
||||||
|
-- , NotInlined "x"
|
||||||
|
-- )
|
||||||
|
example2 :: BidirectionalState (InlineResult, InlineResult, InlineResult)
|
||||||
|
example2 = do
|
||||||
|
x <- tryInline "x"
|
||||||
|
y <- tryInline "y"
|
||||||
|
x' <- tryInline "x"
|
||||||
|
pure (x,y,x')
|
||||||
|
|||||||
@@ -326,6 +326,15 @@ instance S.DatumIso Kexp where
|
|||||||
instance S.DatumIso Program where
|
instance S.DatumIso Program where
|
||||||
datumIso = S.with \prog -> S.datumIso @Lambda >>> prog
|
datumIso = S.with \prog -> S.datumIso @Lambda >>> prog
|
||||||
|
|
||||||
|
-- the printed representation is pretty dishonest in its current
|
||||||
|
-- state. consider the following hoisted program:
|
||||||
|
--
|
||||||
|
-- (letrec ((k (κ () (continue start-ktail 123))))
|
||||||
|
-- (λ (start-ktail)
|
||||||
|
-- (continue k)))
|
||||||
|
--
|
||||||
|
-- here, `start-ktail` is bound in `k`, but the printed representation
|
||||||
|
-- fails to reflect that.
|
||||||
instance S.DatumIso HoistedProgram where
|
instance S.DatumIso HoistedProgram where
|
||||||
datumIso = S.with \prog ->
|
datumIso = S.with \prog ->
|
||||||
S.letLike "letrec"
|
S.letLike "letrec"
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import Gyehoek.Prelude
|
|||||||
import Gyehoek.Jalmot
|
import Gyehoek.Jalmot
|
||||||
import qualified Gyehoek.Sexp as S
|
import qualified Gyehoek.Sexp as S
|
||||||
import Gyehoek.CPS.Hoist (hoistProgram)
|
import Gyehoek.CPS.Hoist (hoistProgram)
|
||||||
|
import Gyehoek.CPS.Contify (contifyProgram)
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
@@ -126,6 +127,9 @@ driver opts = do
|
|||||||
hoistedCps <- hoistProgram closedCps
|
hoistedCps <- hoistProgram closedCps
|
||||||
when opts.dumpHoisted do
|
when opts.dumpHoisted do
|
||||||
hPutStrLn FS.stdout =<< S.encodeWith S.datumIso hoistedCps
|
hPutStrLn FS.stdout =<< S.encodeWith S.datumIso hoistedCps
|
||||||
|
contifiedCps <- contifyProgram hoistedCps
|
||||||
|
when opts.dumpContified do
|
||||||
|
hPutStrLn FS.stdout =<< S.encodeWith S.datumIso contifiedCps
|
||||||
let rt_is p = is (_Just . p) opts.runtime
|
let rt_is p = is (_Just . p) opts.runtime
|
||||||
dumpOrRun opts.dumpStackified (rt_is #Stackify)
|
dumpOrRun opts.dumpStackified (rt_is #Stackify)
|
||||||
(stackifyProgram closedCps)
|
(stackifyProgram closedCps)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ data Options = MkOptions
|
|||||||
, dumpParsed :: Bool
|
, dumpParsed :: Bool
|
||||||
, dumpStackified :: Bool
|
, dumpStackified :: Bool
|
||||||
, dumpHoisted :: Bool
|
, dumpHoisted :: Bool
|
||||||
|
, dumpContified :: Bool
|
||||||
, traceStackified :: Bool
|
, traceStackified :: Bool
|
||||||
, runtime :: Maybe Runtime
|
, runtime :: Maybe Runtime
|
||||||
, inspectWasm :: Bool
|
, inspectWasm :: Bool
|
||||||
@@ -63,6 +64,7 @@ parser = do
|
|||||||
dumpStackified <- switch (long "dump-stackified")
|
dumpStackified <- switch (long "dump-stackified")
|
||||||
dumpParsed <- switch (long "dump-parsed")
|
dumpParsed <- switch (long "dump-parsed")
|
||||||
dumpHoisted <- switch (long "dump-hoisted")
|
dumpHoisted <- switch (long "dump-hoisted")
|
||||||
|
dumpContified <- switch (long "dump-contified")
|
||||||
traceStackified <- switch (long "trace-stackified")
|
traceStackified <- switch (long "trace-stackified")
|
||||||
inspectWasm <- switch $ long "inspect-wasm" <> short 'p'
|
inspectWasm <- switch $ long "inspect-wasm" <> short 'p'
|
||||||
runtime <- option runtimeReader . fold $
|
runtime <- option runtimeReader . fold $
|
||||||
|
|||||||
Reference in New Issue
Block a user