diff options
author | Camil Staps | 2023-01-28 12:48:43 +0100 |
---|---|---|
committer | Camil Staps | 2023-01-28 12:48:43 +0100 |
commit | f84fca3b169d808943b5f329c177870dc87c1d51 (patch) | |
tree | c6af7707ecd8fc52c4ed4804ece707fce941b0be /snug-clean/src/Snug/Compile/Simulate.icl | |
parent | Add 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.icl | 118 |
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" |