Merge pull request #3 from msydneyslaga/gm-m3

Gm m3
This commit was merged in pull request #3.
This commit is contained in:
msydneyslaga
2023-12-01 14:45:08 -07:00
committed by GitHub
2 changed files with 105 additions and 30 deletions

View File

@@ -5,7 +5,7 @@ The *G-Machine*
Motivation Motivation
********** **********
Our initial model, the *Template Instantiation Machine* (TIM) was a very Our initial model, the *Template Instantiator* (TI) was a very
straightforward solution to compilation, but its core design has a major straightforward solution to compilation, but its core design has a major
Achilles' heel, being that Compilation is interleaved with evaluation -- The Achilles' heel, being that Compilation is interleaved with evaluation -- The
heap nodes for supercombinators hold uninstantiated expressions, i.e. raw ASTs heap nodes for supercombinators hold uninstantiated expressions, i.e. raw ASTs
@@ -43,11 +43,11 @@ The process of instantiating a supercombinator goes something like this
4. Push the address to the newly instantiated body onto the stack. 4. Push the address to the newly instantiated body onto the stack.
.. literalinclude:: /../../src/TIM.hs .. literalinclude:: /../../src/TI.hs
:dedent: :dedent:
:start-after: -- >> [ref/scStep] :start-after: -- >> [ref/scStep]
:end-before: -- << [ref/scStep] :end-before: -- << [ref/scStep]
:caption: src/TIM.hs :caption: src/TI.hs
Instantiating the supercombinator's body in this way is the root of our Instantiating the supercombinator's body in this way is the root of our
Achilles' heel. Traversing a tree structure is a very non-linear task unfit for Achilles' heel. Traversing a tree structure is a very non-linear task unfit for
@@ -125,15 +125,12 @@ Core Transition Rules
.. math:: .. math::
\gmrule \gmrule
{ \mathtt{Push} \; n : i { \mathtt{Push} \; n : i
& a_0 : \ldots : a_{n+1} : s & a_0 : \ldots : a_n : s
& h & h
\begin{bmatrix}
a_{n+1} : \mathtt{NAp} \; a_n \; a'_n
\end{bmatrix}
& m & m
} }
{ i { i
& a'_n : a_0 : \ldots : a_{n+1} : s & a_n : a_0 : \ldots : a_n : s
& h & h
& m & m
} }
@@ -190,9 +187,9 @@ Core Transition Rules
& m & m
} }
8. When a global node is on top of the stack (and the correct number of 8. When a supercombinator is on top of the stack (and the correct number of
arguments have been provided), :code:`Unwind` jumps to the supercombinator's arguments have been provided), :code:`Unwind` sets up the stack and jumps to
code (:math:`\beta`-reduction) the supercombinator's code (:math:`\beta`-reduction)
.. math:: .. math::
\gmrule \gmrule
@@ -200,12 +197,15 @@ Core Transition Rules
& a_0 : \ldots : a_n : s & a_0 : \ldots : a_n : s
& h & h
\begin{bmatrix} \begin{bmatrix}
a_0 : \mathtt{NGlobal} \; n \; c a_0 : \mathtt{NGlobal} \; n \; c \\
a_1 : \mathtt{NAp} \; a_0 \; e_1 \\
\vdots \\
a_n : \mathtt{NAp} \; a_{n-1} \; e_n \\
\end{bmatrix} \end{bmatrix}
& m & m
} }
{ c { c
& a_0 : \ldots : a_n : s & e_1 : \ldots : e_n : a_n : s
& h & h
& m & m
} }
@@ -266,6 +266,26 @@ Core Transition Rules
& m & m
} }
12. Allocate uninitialised heap space
.. math::
\gmrule
{ \mathtt{Alloc} \; n : i
& s
& h
& m
}
{ i
& a_1 : \ldots : a_n : s
& h
\begin{bmatrix}
a_1 : \mathtt{NUninitialised} \\
\vdots \\
a_n : \mathtt{NUninitialised} \\
\end{bmatrix}
& m
}
Extension Rules Extension Rules
--------------- ---------------

View File

@@ -20,8 +20,9 @@ import Text.Printf
import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint hiding ((<>))
import Text.PrettyPrint.HughesPJ (maybeParens) import Text.PrettyPrint.HughesPJ (maybeParens)
import Data.Foldable (traverse_) import Data.Foldable (traverse_)
import Debug.Trace
import System.IO (Handle, hPutStrLn) import System.IO (Handle, hPutStrLn)
import Data.Heap import Data.Heap as Heap
import Core import Core
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
@@ -47,6 +48,7 @@ data Instr = Unwind
| Slide Int | Slide Int
| Update Int | Update Int
| Pop Int | Pop Int
| Alloc Int
deriving (Show, Eq) deriving (Show, Eq)
data Node = NNum Int data Node = NNum Int
@@ -56,6 +58,7 @@ data Node = NNum Int
-- the pre-compiled code :3 -- the pre-compiled code :3
| NGlobal Int Code | NGlobal Int Code
| NInd Addr | NInd Addr
| NUninitialised
deriving (Show, Eq) deriving (Show, Eq)
data Stats = Stats data Stats = Stats
@@ -123,6 +126,7 @@ step st = case head (st ^. gmCode) of
Slide n -> slide n st Slide n -> slide n st
Pop n -> pop n st Pop n -> pop n st
Update n -> update n st Update n -> update n st
Alloc n -> alloc n st
where where
pushGlobal :: Name -> GmState -> GmState pushGlobal :: Name -> GmState -> GmState
@@ -154,7 +158,7 @@ step st = case head (st ^. gmCode) of
& gmStats . stsAllocations %~ succ -- & gmStats . stsAllocations %~ succ --
where where
s' = a : s s' = a : s
(h',a) = alloc h (NNum n) (h',a) = Heap.alloc h (NNum n)
m' = (n',a) : m m' = (n',a) : m
where where
m = st ^. gmEnv m = st ^. gmEnv
@@ -173,8 +177,8 @@ step st = case head (st ^. gmCode) of
-- s = st ^. gmStack -- s = st ^. gmStack
-- h = st ^. gmHeap -- h = st ^. gmHeap
s' = a : s -- s' = a : s
(h',a) = alloc h (NNum n) -- (h',a) = alloc h (NNum n)
mkAp :: GmState -> GmState mkAp :: GmState -> GmState
mkAp st = st mkAp st = st
@@ -188,23 +192,18 @@ step st = case head (st ^. gmCode) of
h = st ^. gmHeap h = st ^. gmHeap
s' = a : ss s' = a : ss
(h',a) = alloc h (NAp f x) (h',a) = Heap.alloc h (NAp f x)
-- a `Push n` instruction pushes the address of (n+1)-th argument onto -- a `Push n` instruction pushes the address of (n+1)-th argument onto
-- the stack. this means that the nth node on the stack is assumed to be -- the stack.
-- an application. the (n+1)-th argument is the rhs of that application.
push :: Int -> GmState -> GmState push :: Int -> GmState -> GmState
push n st = st push n st = st
& gmCode %~ drop 1 & gmCode %~ drop 1
& gmStack .~ s' & gmStack %~ (a:)
where where
s = st ^. gmStack
h = st ^. gmHeap h = st ^. gmHeap
s = st ^. gmStack
s' = arg : s a = s !! n
argAp = s !! (n+1)
arg = case hLookupUnsafe argAp h of
NAp _ a -> a
-- 'slide' the top of the stack `n` entries downwards, popping any -- 'slide' the top of the stack `n` entries downwards, popping any
-- entries along the way. -- entries along the way.
@@ -231,13 +230,29 @@ step st = case head (st ^. gmCode) of
(e:s) = st ^. gmStack (e:s) = st ^. gmStack
an = s !! n an = s !! n
h' = st ^. gmHeap h' = st ^. gmHeap
& Data.Heap.update an (NInd e) & Heap.update an (NInd e)
pop :: Int -> GmState -> GmState pop :: Int -> GmState -> GmState
pop n st = st pop n st = st
& gmCode %~ drop 1 & gmCode %~ drop 1
& gmStack %~ drop n & gmStack %~ drop n
alloc :: Int -> GmState -> GmState
alloc n st = st
& gmCode %~ drop 1
& gmStack .~ s'
& gmHeap .~ h'
where
s = st ^. gmStack
h = st ^. gmHeap
s' = ns ++ s
(h',ns) = allocNode n h
allocNode :: Int -> GmHeap -> (GmHeap, [Addr])
allocNode 0 g = (g,[])
allocNode k g = allocNode (k-1) g' & _2 %~ (a:)
where (g',a) = Heap.alloc g NUninitialised
-- the complex heart of the G-machine -- the complex heart of the G-machine
unwind :: GmState -> GmState unwind :: GmState -> GmState
unwind st = case hLookupUnsafe a h of unwind st = case hLookupUnsafe a h of
@@ -248,10 +263,20 @@ step st = case head (st ^. gmCode) of
-- leave the Unwind instr; continue unwinding -- leave the Unwind instr; continue unwinding
& gmStack %~ (f:) & gmStack %~ (f:)
-- assumes length s < d (i.e. enough args have been supplied) -- assumes length s < d (i.e. enough args have been supplied)
NGlobal d c -> st NGlobal n c -> st
-- 'jump' to global's code by replacing our current -- 'jump' to global's code by replacing our current
-- code with `c` -- code with `c`
& gmCode .~ c & gmCode .~ c
& gmStack .~ s'
where
s' = args ++ drop n s
args = getArgs $ take (n+1) s
getArgs :: Stack -> [Addr]
getArgs (_:ss) = fmap arg ss
where
arg (hViewUnsafe h -> NAp _ x) = x
-- follow indirection -- follow indirection
NInd a -> st NInd a -> st
-- leave the Unwind instr; continue unwinding. -- leave the Unwind instr; continue unwinding.
@@ -316,6 +341,35 @@ buildInitialHeap (Program ss) = mapAccumL allocateSc mempty compiled
<> [MkAp] <> [MkAp]
-- << [ref/compileC] -- << [ref/compileC]
compileC g (Let NonRec bs e) =
mconcat binders <> compileC g' e <> [Slide d]
where
d = length bs
(g',binders) = mapAccumL compileBinder (argOffset d g) addressed
-- kinda gross. revisit this
addressed = bs `zip` reverse [0 .. d-1]
compileBinder :: Env -> (Binding, Int) -> (Env, Code)
compileBinder m (k := v, a) = (m',c)
where
m' = (k,a) : m
-- make note that we use m rather than m'!
c = compileC m v
compileC g (Let Rec bs e) = Alloc d : initialisers <> body <> [Slide d]
where
d = length bs
g' = fmap toEnv addressed ++ argOffset d g
toEnv (k := _, a) = (k,a)
-- kinda gross. revisit this
addressed = bs `zip` reverse [0 .. d-1]
initialisers = mconcat $ compileBinder <$> addressed
body = compileC g' e
compileBinder :: (Binding, Int) -> Code
compileBinder (k := v, a) = compileC g' v <> [Update a]
-- | offset each address in the environment by n -- | offset each address in the environment by n
argOffset :: Int -> Env -> Env argOffset :: Int -> Env -> Env
argOffset n = each . _2 %~ (+n) argOffset n = each . _2 %~ (+n)
@@ -410,6 +464,7 @@ showNodeAtP p st a = case hLookup a h of
where pprec = maybeParens (p > 0) where pprec = maybeParens (p > 0)
Just (NInd a) -> pprec $ "NInd -> " <> showNodeAtP (p+1) st a Just (NInd a) -> pprec $ "NInd -> " <> showNodeAtP (p+1) st a
where pprec = maybeParens (p > 0) where pprec = maybeParens (p > 0)
Just NUninitialised -> "<uninitialised>"
Nothing -> "<invalid address>" Nothing -> "<invalid address>"
where h = st ^. gmHeap where h = st ^. gmHeap