FrameIntel.hs 2.99 KB
{-# LANGUAGE UndecidableInstances, TypeSynonymInstances, FlexibleInstances,
      GeneralizedNewtypeDeriving #-}

-- this module is part of the risc386 simulator (IntelMain)

module FrameIntel where

-- import Data.List -- reverse
import Data.Map (Map)
import qualified Data.Map as Map
import Text.PrettyPrint

import Util -- splitmap
import GenSym
import Frame
import Intel
-- import TreePrinter (Pretty(..))

type IntelFrame = Frame [Instr]

-- data IntelFrame = IntelFrame String [Acc] [Instr]

instance Pretty IntelFrame where
    ppr (Frame f il) = 
      nest 8 (text ".global" <+> nest 8 (text f))
      $+$ nest 8 (text ".type" <+> nest 8 (text f <> comma <+> text "@function"))
      $+$ text f <> colon
      $+$ ppr il

instance Pretty [IntelFrame] where
   ppr fs = nest 8 (text ".intel_syntax")
            $+$ (vcat $ map ppr fs)

{- The code of each function is split up into a collection of blocks,
   beginning with a LABEL, ending with a JMP or RET.

   No LABEL within a block.

-}

type IBlock = [Instr]
type IBlockMap = Map Label IBlock

data IBlockFrame = IBlockFrame 
  String      -- name of the function 
  IBlockMap  -- map from labels to blocks (contains at least first label)

type FrameMap = Map Label IBlockFrame

instance Pretty IBlockFrame where
    ppr (IBlockFrame f blocks) 
        | Just (b1, rest) <- splitMap f blocks = 
      nest 8 (text ".global" <+> nest 8 (text f))
      $+$ nest 8 (text ".type" <+> nest 8 (text f <> comma <+> text "@function"))
      $+$ text f <> colon
      $+$ ppr b1 
      $+$ ppr (Map.foldrWithKey (\ k rs ss -> LABEL k : rs ++ ss) [] rest)

instance Pretty [IBlockFrame] where
   ppr fs = vcat $ map ppr fs

-- divide a frame into blocks ;  
-- the first block inherits its label from the frame
iBlocksFrame :: IntelFrame -> IBlockFrame
iBlocksFrame (Frame f ss) =
  (IBlockFrame f (insertIBlocks (LABEL f : ss) Map.empty))

  
-- insertBlocks (ss, map_acc) = map
insertIBlocks :: [Instr] -> IBlockMap -> IBlockMap
insertIBlocks [] acc = acc
insertIBlocks (LABEL l : ss) acc =
  let (block, rest) = chopOffIBlock ss
  in insertIBlocks rest (Map.insert l block acc)  
insertIBlocks ss acc = insertIBlocks (LABEL ("Ldummy" ++ show (length ss))  : ss) acc

-- chopOffBlock (l', ss) = (l, block, rest)
-- Precondition: ss begins with LABEL l
chopOffIBlock :: [Instr] -> ([Instr], [Instr])
chopOffIBlock ss =    
  let (block, rest) = chopOffIBlock' ss []
  in  (reverse block, rest)

-- chopOffBlock' ss block_acc = (rev_block, ss_rest)
chopOffIBlock' :: [Instr] -> [Instr] -> ([Instr], [Instr])
chopOffIBlock' [] acc = error "Reached the end of a block that does not end with a label or a jump. The last instruction must be a jump, typically 'ret'."
chopOffIBlock' ss@(LABEL l : _) acc = (JMP l : acc, ss) -- insert artificial jump 
chopOffIBlock' (s@RET : ss) acc =  (s : acc, ss)
chopOffIBlock' (s@(JMP _) : ss) acc =  (s : acc, ss)
-- conditional jump not the end of a block
-- chopOffIBlock' (s@(J _ _) : ss) acc = (s : acc, ss) 
chopOffIBlock' (s : ss) acc = chopOffIBlock' ss (s : acc)