aboutsummaryrefslogtreecommitdiff
path: root/snug-clean/src/Snug/Compile/Simulate.icl
diff options
context:
space:
mode:
authorCamil Staps2023-01-28 12:48:43 +0100
committerCamil Staps2023-01-28 12:48:43 +0100
commitf84fca3b169d808943b5f329c177870dc87c1d51 (patch)
treec6af7707ecd8fc52c4ed4804ece707fce941b0be /snug-clean/src/Snug/Compile/Simulate.icl
parentAdd compilation of constructors and basic values (diff)
Add stack simulator for compilation
Diffstat (limited to 'snug-clean/src/Snug/Compile/Simulate.icl')
-rw-r--r--snug-clean/src/Snug/Compile/Simulate.icl118
1 files changed, 118 insertions, 0 deletions
diff --git a/snug-clean/src/Snug/Compile/Simulate.icl b/snug-clean/src/Snug/Compile/Simulate.icl
new file mode 100644
index 0000000..d1d65ac
--- /dev/null
+++ b/snug-clean/src/Snug/Compile/Simulate.icl
@@ -0,0 +1,118 @@
+implementation module Snug.Compile.Simulate
+
+import StdEnv
+
+import Control.Monad
+import Control.Monad.Identity
+import Control.Monad.State
+import Data.Functor
+
+import MIPS.MIPS32
+import Snug.Compile.ABI
+import Snug.Syntax
+
+:: SimulationState =
+ { instrs :: ![[Instruction]]
+ , hp_offset :: !Int
+ , stack :: ![StackValue]
+ }
+
+:: StackValue
+ = SVImmediate !Immediate
+ | SVRegOffset !Register !Offset /* value is reg + offset */
+
+simulate :: !(Simulator a) -> [Instruction]
+simulate sim = flatten (reverse (execState sim initial).instrs)
+where
+ // TODO: when finishing:
+ // - check that the stack is empty
+ // - update heap pointer
+ initial =
+ { instrs = []
+ , hp_offset = 0
+ , stack = []
+ }
+
+add :: ![Instruction] -> Simulator ()
+add is = modify \s -> {s & instrs=[is:s.instrs]}
+
+push :: StackValue -> Simulator ()
+push sv = modify \s -> {s & stack=[sv:s.stack]}
+
+pop :: Simulator StackValue
+pop =
+ getState >>= \{stack} ->
+ modify (\s -> {s & stack=tl stack}) $> hd stack
+
+write_heap :: !StackValue -> Simulator StackValue
+write_heap sv =
+ getState >>= \{hp_offset} ->
+ storeStackValue sv hp_offset HeapPtr >>|
+ modify (\s -> {s & hp_offset=hp_offset+4}) $>
+ SVRegOffset HeapPtr hp_offset
+
+storeStackValue :: !StackValue !Offset !Register -> Simulator ()
+storeStackValue (SVImmediate (Immediate i)) doffset dreg
+ | i == 0 = add
+ [ StoreWord R0 doffset dreg
+ ]
+ | 0 <= i && i < 0x10000 = add
+ [ OrImmediate TempImm R0 (Immediate i)
+ , StoreWord TempImm doffset dreg
+ ]
+ | 0 > i && i >= -0x8000 = add
+ [ AddImmediate Signed TempImm R0 (Immediate i)
+ , StoreWord TempImm doffset dreg
+ ]
+ | otherwise = add
+ [ LoadUpperImmediate TempImm (Immediate (i >> 16))
+ , OrImmediate TempImm TempImm (Immediate (i bitand 0xffff))
+ , StoreWord TempImm doffset dreg
+ ]
+storeStackValue (SVImmediate imm=:(Address _ _)) doffset dreg = add
+ [ LoadAddress TempImm imm
+ , StoreWord TempImm doffset dreg
+ ]
+storeStackValue (SVRegOffset reg 0) doffset dreg = add
+ [ StoreWord reg doffset dreg
+ ]
+storeStackValue (SVRegOffset reg offset) doffset dreg = add
+ [ AddImmediate Signed TempImm reg (Immediate offset)
+ , StoreWord TempImm doffset dreg
+ ]
+
+buildCons :: !Label !Int -> Simulator ()
+buildCons cons nargs =
+ write_heap (SVImmediate (Address 2 cons)) >>= \addr ->
+ mapM_ (\_ -> pop >>= write_heap) [1..nargs] >>|
+ push addr
+
+pushBasicValue :: !BasicValue -> Simulator ()
+pushBasicValue val = push (SVImmediate (Immediate imm))
+where
+ imm = case val of
+ BVInt i -> i
+ BVChar c -> toInt c
+
+indirectAndEval :: Simulator ()
+indirectAndEval =
+ pop >>= \sv ->
+ case sv of
+ SVRegOffset HeapPtr offset ->
+ add
+ // Build indirection
+ [ LoadAddress TempImm (Address 0 (functionLabel "" NodeEntry "indir"))
+ , StoreWord TempImm 0 FrontEvalPtr
+ ] >>|
+ storeStackValue sv 4 FrontEvalPtr >>|
+ add
+ // Evaluate
+ [ AddImmediate Signed FrontEvalPtr HeapPtr (Immediate offset)
+ , Jump NoLink (Direct (Address 0 "eval"))
+ ] >>|
+ getState >>= \{hp_offset} ->
+ add
+ [ AddImmediate Signed HeapPtr HeapPtr (Immediate hp_offset)
+ ]
+ _ ->
+ abort "unexpected top of stack in indirect\n"