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 4 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"