% % (c) The University of Glasgow 2006 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % \section[CgMonad]{The code generation monad} See the beginning of the top-level @CodeGen@ module, to see how this monadic stuff fits into the Big Picture. \begin{code}
{-# OPTIONS -fno-warn-tabs #-}
-- The above warning supression flag is a temporary kludge.
-- While working on this module you are encouraged to remove it and
-- detab the module (please do the detabbing in a separate patch). See
--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
-- for details

{-# LANGUAGE BangPatterns #-}
module CgMonad (
	Code,	-- type
	FCode,	-- type

	initC, thenC, thenFC, listCs, listFCs, mapCs, mapFCs,
	returnFC, fixC, fixC_, checkedAbsC, 
	stmtC, stmtsC, labelC, emitStmts, nopC, whenC, newLabelC,
	newUnique, newUniqSupply, 

	CgStmts, emitCgStmts, forkCgStmts, cgStmtsToBlocks,
	getCgStmts', getCgStmts,
	noCgStmts, oneCgStmt, consCgStmt,

	getCmm,
	emitDecl, emitProc, emitSimpleProc,

	forkLabelledCode,
	forkClosureBody, forkStatics, forkAlts, forkEval,
	forkEvalHelp, forkProc, codeOnly,
	SemiTaggingStuff, ConTagZ,

	EndOfBlockInfo(..),
	setEndOfBlockInfo, getEndOfBlockInfo,

	setSRT, getSRT,
	setSRTLabel, getSRTLabel, 
	setTickyCtrLabel, getTickyCtrLabel,

	StackUsage(..), HeapUsage(..),
	VirtualSpOffset, VirtualHpOffset,
	initStkUsage, initHpUsage,
	getHpUsage,  setHpUsage,
	heapHWM,

	getModuleName,

	Sequel(..), -- ToDo: unabstract?

	-- ideally we wouldn't export these, but some other modules access internal state
	getState, setState, getInfoDown, getDynFlags, getThisPackage, 

	-- more localised access to monad state	
	getStkUsage, setStkUsage,
	getBinds, setBinds, getStaticBinds,

	-- out of general friendliness, we also export ...
	CgInfoDownwards(..), CgState(..)	-- non-abstract
    ) where

#include "HsVersions.h"

import {-# SOURCE #-} CgBindery ( CgBindings, nukeVolatileBinds )

import DynFlags
import BlockId
import OldCmm
import OldCmmUtils
import CLabel
import StgSyn (SRT)
import ClosureInfo( ConTagZ )
import SMRep
import Module
import Id
import VarEnv
import OrdList
import Unique
import UniqSupply
import Outputable

import Control.Monad
import Data.List

infixr 9 `thenC`	-- Right-associative!
infixr 9 `thenFC`
\end{code} %************************************************************************ %* * \subsection[CgMonad-environment]{Stuff for manipulating environments} %* * %************************************************************************ This monadery has some information that it only passes {\em downwards}, as well as some ``state'' which is modified as we go along. \begin{code}
data CgInfoDownwards	-- information only passed *downwards* by the monad
  = MkCgInfoDown {
	cgd_dflags  :: DynFlags,
	cgd_mod     :: Module,		-- Module being compiled
	cgd_statics :: CgBindings,	-- [Id -> info] : static environment
	cgd_srt_lbl :: CLabel,		-- label of the current SRT
        cgd_srt     :: SRT,		-- the current SRT
	cgd_ticky   :: CLabel,		-- current destination for ticky counts
	cgd_eob     :: EndOfBlockInfo	-- Info for stuff to do at end of basic block:
  }

initCgInfoDown :: DynFlags -> Module -> CgInfoDownwards
initCgInfoDown dflags mod
  = MkCgInfoDown {	cgd_dflags  = dflags,
			cgd_mod     = mod,
			cgd_statics = emptyVarEnv,
			cgd_srt_lbl = error "initC: srt_lbl",
			cgd_srt     = error "initC: srt",
			cgd_ticky   = mkTopTickyCtrLabel,
			cgd_eob     = initEobInfo }

data CgState
  = MkCgState {
     cgs_stmts :: OrdList CgStmt,	  -- Current proc
     cgs_tops  :: OrdList CmmDecl,
	-- Other procedures and data blocks in this compilation unit
	-- Both the latter two are ordered only so that we can 
	-- reduce forward references, when it's easy to do so
     
     cgs_binds :: CgBindings,	-- [Id -> info] : *local* bindings environment
     				-- Bindings for top-level things are given in
				-- the info-down part
     
     cgs_stk_usg :: StackUsage,
     cgs_hp_usg  :: HeapUsage,
     
     cgs_uniqs :: UniqSupply }

initCgState :: UniqSupply -> CgState
initCgState uniqs
  = MkCgState { cgs_stmts = nilOL, cgs_tops = nilOL,
		cgs_binds = emptyVarEnv, 
		cgs_stk_usg = initStkUsage, 
		cgs_hp_usg = initHpUsage,
		cgs_uniqs = uniqs }
\end{code} @EndOfBlockInfo@ tells what to do at the end of this block of code or, if the expression is a @case@, what to do at the end of each alternative. \begin{code}
data EndOfBlockInfo
  = EndOfBlockInfo
	VirtualSpOffset   -- Args Sp: trim the stack to this point at a
			  -- return; push arguments starting just
			  -- above this point on a tail call.
			  
			  -- This is therefore the stk ptr as seen
			  -- by a case alternative.
	Sequel

initEobInfo :: EndOfBlockInfo
initEobInfo = EndOfBlockInfo 0 OnStack
\end{code} Any addressing modes inside @Sequel@ must be ``robust,'' in the sense that it must survive stack pointer adjustments at the end of the block. \begin{code}
data Sequel
  = OnStack 		-- Continuation is on the stack

  | CaseAlts
	  CLabel     -- Jump to this; if the continuation is for a vectored
		     -- case this might be the label of a return vector
	  SemiTaggingStuff
	  Id	      -- The case binder, only used to see if it's dead

type SemiTaggingStuff
  = Maybe			-- Maybe[1] we don't have any semi-tagging stuff...
     ([(ConTagZ, CmmLit)],	-- Alternatives
      CmmLit)			-- Default (will be a can't happen RTS label if can't happen)

-- The case branch is executed only from a successful semitagging
-- venture, when a case has looked at a variable, found that it's
-- evaluated, and wants to load up the contents and go to the join
-- point.
\end{code} %************************************************************************ %* * CgStmt type %* * %************************************************************************ The CgStmts type is what the code generator outputs: it is a tree of statements, including in-line labels. The job of flattenCgStmts is to turn this into a list of basic blocks, each of which ends in a jump statement (either a local branch or a non-local jump). \begin{code}
type CgStmts = OrdList CgStmt

data CgStmt
  = CgStmt  CmmStmt
  | CgLabel BlockId
  | CgFork  BlockId CgStmts

flattenCgStmts :: BlockId -> CgStmts -> [CmmBasicBlock]
flattenCgStmts id stmts = 
	case flatten (fromOL stmts) of
	  ([],blocks)    -> blocks
	  (block,blocks) -> BasicBlock id block : blocks
 where
  flatten [] = ([],[])

  -- A label at the end of a function or fork: this label must not be reachable,
  -- but it might be referred to from another BB that also isn't reachable.
  -- Eliminating these has to be done with a dead-code analysis.  For now,
  -- we just make it into a well-formed block by adding a recursive jump.
  flatten [CgLabel id]
    = ( [CmmBranch id], [BasicBlock id [CmmBranch id]] )

  -- A jump/branch: throw away all the code up to the next label, because
  -- it is unreachable.  Be careful to keep forks that we find on the way.
  flatten (CgStmt stmt : stmts)
    | isJump stmt
    = case dropWhile isOrdinaryStmt stmts of
	[]                     -> ( [stmt], [] )
	[CgLabel id]	       -> ( [stmt], [BasicBlock id [CmmBranch id]])
	(CgLabel id : stmts)   -> ( [stmt], BasicBlock id block : blocks )
	    where (block,blocks) = flatten stmts
	(CgFork fork_id stmts : ss) -> 
	   flatten (CgFork fork_id stmts : CgStmt stmt : ss)
        (CgStmt {} : _) -> panic "CgStmt not seen as ordinary"

  flatten (s:ss) = 
	case s of
	  CgStmt stmt -> (stmt:block,blocks)
	  CgLabel id  -> ([CmmBranch id],BasicBlock id block:blocks)
	  CgFork fork_id stmts -> 
		(block, BasicBlock fork_id fork_block : fork_blocks ++ blocks)
		where (fork_block, fork_blocks) = flatten (fromOL stmts)
    where (block,blocks) = flatten ss

isJump :: CmmStmt -> Bool
isJump (CmmJump _ _) = True
isJump (CmmBranch _) = True
isJump (CmmSwitch _ _) = True
isJump (CmmReturn _) = True
isJump _ = False

isOrdinaryStmt :: CgStmt -> Bool
isOrdinaryStmt (CgStmt _) = True
isOrdinaryStmt _ = False
\end{code} %************************************************************************ %* * Stack and heap models %* * %************************************************************************ \begin{code}
type VirtualHpOffset = WordOff	-- Both are in
type VirtualSpOffset = WordOff	-- units of words

data StackUsage 
  = StackUsage {
	virtSp :: VirtualSpOffset,
		-- Virtual offset of topmost allocated slot

	frameSp :: VirtualSpOffset,
		-- Virtual offset of the return address of the enclosing frame.
		-- This RA describes the liveness/pointedness of
		-- all the stack from frameSp downwards
		-- INVARIANT: less than or equal to virtSp

	 freeStk :: [VirtualSpOffset], 
		-- List of free slots, in *increasing* order
		-- INVARIANT: all <= virtSp
		-- All slots <= virtSp are taken except these ones

	 realSp :: VirtualSpOffset,	
		-- Virtual offset of real stack pointer register

	 hwSp :: VirtualSpOffset
  }		   -- Highest value ever taken by virtSp

-- INVARIANT: The environment contains no Stable references to
-- 	      stack slots below (lower offset) frameSp
--	      It can contain volatile references to this area though.

data HeapUsage =
  HeapUsage {
	virtHp :: VirtualHpOffset,	-- Virtual offset of highest-allocated word
	realHp :: VirtualHpOffset	-- realHp: Virtual offset of real heap ptr
  }
\end{code} The heap high water mark is the larger of virtHp and hwHp. The latter is only records the high water marks of forked-off branches, so to find the heap high water mark you have to take the max of virtHp and hwHp. Remember, virtHp never retreats! Note Jan 04: ok, so why do we only look at the virtual Hp?? \begin{code}
heapHWM :: HeapUsage -> VirtualHpOffset
heapHWM = virtHp
\end{code} Initialisation. \begin{code}
initStkUsage :: StackUsage
initStkUsage = StackUsage {
			virtSp = 0,
			frameSp = 0,
			freeStk = [],
			realSp = 0,
			hwSp = 0
	       }
		
initHpUsage :: HeapUsage 
initHpUsage = HeapUsage {
	      	virtHp = 0,
		realHp = 0
	      }
\end{code} @stateIncUsage@$~e_1~e_2$ incorporates in $e_1$ the stack and heap high water marks found in $e_2$. \begin{code}
stateIncUsage :: CgState -> CgState -> CgState
stateIncUsage s1 s2@(MkCgState { cgs_stk_usg = stk_usg, cgs_hp_usg = hp_usg })
     = s1 { cgs_hp_usg  = cgs_hp_usg  s1 `maxHpHw`  virtHp hp_usg,
	    cgs_stk_usg = cgs_stk_usg s1 `maxStkHw` hwSp   stk_usg }
       `addCodeBlocksFrom` s2
		
stateIncUsageEval :: CgState -> CgState -> CgState
stateIncUsageEval s1 s2
     = s1 { cgs_stk_usg = cgs_stk_usg s1 `maxStkHw` hwSp (cgs_stk_usg s2) }
       `addCodeBlocksFrom` s2
	-- We don't max the heap high-watermark because stateIncUsageEval is
	-- used only in forkEval, which in turn is only used for blocks of code
	-- which do their own heap-check.

addCodeBlocksFrom :: CgState -> CgState -> CgState
-- Add code blocks from the latter to the former
-- (The cgs_stmts will often be empty, but not always; see codeOnly)
s1 `addCodeBlocksFrom` s2
  = s1 { cgs_stmts = cgs_stmts s1 `appOL` cgs_stmts s2,
	 cgs_tops  = cgs_tops  s1 `appOL` cgs_tops  s2 }

maxHpHw :: HeapUsage -> VirtualHpOffset -> HeapUsage
hp_usg `maxHpHw` hw = hp_usg { virtHp = virtHp hp_usg `max` hw }

maxStkHw :: StackUsage -> VirtualSpOffset -> StackUsage
stk_usg `maxStkHw` hw = stk_usg { hwSp = hwSp stk_usg `max` hw }
\end{code} %************************************************************************ %* * The FCode monad %* * %************************************************************************ \begin{code}
newtype FCode a = FCode (CgInfoDownwards -> CgState -> (a, CgState))
type Code       = FCode ()

instance Monad FCode where
	(>>=) = thenFC
	return = returnFC

{-# INLINE thenC #-}
{-# INLINE thenFC #-}
{-# INLINE returnFC #-}
\end{code} The Abstract~C is not in the environment so as to improve strictness. \begin{code}
initC :: DynFlags -> Module -> FCode a -> IO a

initC dflags mod (FCode code)
  = do	{ uniqs <- mkSplitUniqSupply 'c'
	; case code (initCgInfoDown dflags mod) (initCgState uniqs) of
	      (res, _) -> return res
	}

returnFC :: a -> FCode a
returnFC val = FCode (\_ state -> (val, state))
\end{code} \begin{code}
thenC :: Code -> FCode a -> FCode a
thenC (FCode m) (FCode k) = 
  	FCode (\info_down state -> let (_,new_state) = m info_down state in 
  		k info_down new_state)

listCs :: [Code] -> Code
listCs [] = return ()
listCs (fc:fcs) = do
	fc
	listCs fcs
   	
mapCs :: (a -> Code) -> [a] -> Code
mapCs = mapM_
\end{code} \begin{code}
thenFC	:: FCode a -> (a -> FCode c) -> FCode c
thenFC (FCode m) k = FCode (
	\info_down state ->
		let 
                        (m_result, new_state) = m info_down state
                        (FCode kcode) = k m_result
		in 
			kcode info_down new_state
	)

listFCs :: [FCode a] -> FCode [a]
listFCs = sequence

mapFCs :: (a -> FCode b) -> [a] -> FCode [b]
mapFCs = mapM
\end{code} And the knot-tying combinator: \begin{code}
fixC :: (a -> FCode a) -> FCode a
fixC fcode = FCode (
	\info_down state -> 
		let
			FCode fc = fcode v
			result@(v,_) = fc info_down state
			--	    ^--------^
		in
			result
	)

fixC_ :: (a -> FCode a) -> FCode ()
fixC_ fcode = fixC fcode >> return ()
\end{code} %************************************************************************ %* * Operators for getting and setting the state and "info_down". %* * %************************************************************************ \begin{code}
getState :: FCode CgState
getState = FCode $ \_ state -> (state,state)

setState :: CgState -> FCode ()
setState state = FCode $ \_ _ -> ((),state)

getStkUsage :: FCode StackUsage
getStkUsage = do
	state <- getState
	return $ cgs_stk_usg state

setStkUsage :: StackUsage -> Code
setStkUsage new_stk_usg = do
	state <- getState
	setState $ state {cgs_stk_usg = new_stk_usg}

getHpUsage :: FCode HeapUsage
getHpUsage = do
	state <- getState
	return $ cgs_hp_usg state
	
setHpUsage :: HeapUsage -> Code
setHpUsage new_hp_usg = do
	state <- getState
	setState $ state {cgs_hp_usg = new_hp_usg}

getBinds :: FCode CgBindings
getBinds = do
	state <- getState
	return $ cgs_binds state
	
setBinds :: CgBindings -> FCode ()
setBinds new_binds = do
	state <- getState
	setState $ state {cgs_binds = new_binds}

getStaticBinds :: FCode CgBindings
getStaticBinds = do
	info  <- getInfoDown
	return (cgd_statics info)

withState :: FCode a -> CgState -> FCode (a,CgState)
withState (FCode fcode) newstate = FCode $ \info_down state -> 
	let (retval, state2) = fcode info_down newstate in ((retval,state2), state)

newUniqSupply :: FCode UniqSupply
newUniqSupply = do
	state <- getState
	let (us1, us2) = splitUniqSupply (cgs_uniqs state)
	setState $ state { cgs_uniqs = us1 }
	return us2

newUnique :: FCode Unique
newUnique = do
	us <- newUniqSupply
	return (uniqFromSupply us)

------------------
getInfoDown :: FCode CgInfoDownwards
getInfoDown = FCode $ \info_down state -> (info_down,state)

getDynFlags :: FCode DynFlags
getDynFlags = liftM cgd_dflags getInfoDown

getThisPackage :: FCode PackageId
getThisPackage = liftM thisPackage getDynFlags

withInfoDown :: FCode a -> CgInfoDownwards -> FCode a
withInfoDown (FCode fcode) info_down = FCode $ \_ state -> fcode info_down state 

doFCode :: FCode a -> CgInfoDownwards -> CgState -> (a,CgState)
doFCode (FCode fcode) info_down state = fcode info_down state
\end{code} %************************************************************************ %* * Forking %* * %************************************************************************ @forkClosureBody@ takes a code, $c$, and compiles it in a completely fresh environment, except that: - compilation info and statics are passed in unchanged. The current environment is passed on completely unaltered, except that abstract C from the fork is incorporated. @forkProc@ takes a code and compiles it in the current environment, returning the basic blocks thus constructed. The current environment is passed on completely unchanged. It is pretty similar to @getBlocks@, except that the latter does affect the environment. @forkStatics@ $fc$ compiles $fc$ in an environment whose statics come from the current bindings, but which is otherwise freshly initialised. The Abstract~C returned is attached to the current state, but the bindings and usage information is otherwise unchanged. \begin{code}
forkClosureBody :: Code -> Code
forkClosureBody body_code
  = do	{ info <- getInfoDown
	; us   <- newUniqSupply
	; state <- getState
   	; let	body_info_down = info { cgd_eob = initEobInfo }
		((),fork_state)	= doFCode body_code body_info_down 
					  (initCgState us)
	; ASSERT( isNilOL (cgs_stmts fork_state) )
	  setState $ state `addCodeBlocksFrom` fork_state }
	
forkStatics :: FCode a -> FCode a
forkStatics body_code
  = do	{ info  <- getInfoDown
	; us    <- newUniqSupply
	; state <- getState
	; let	rhs_info_down = info { cgd_statics = cgs_binds state,
				       cgd_eob     = initEobInfo }
		(result, fork_state_out) = doFCode body_code rhs_info_down 
						   (initCgState us)
	; ASSERT( isNilOL (cgs_stmts fork_state_out) )
	  setState (state `addCodeBlocksFrom` fork_state_out)
	; return result }

forkProc :: Code -> FCode CgStmts
forkProc body_code
  = do	{ info_down <- getInfoDown
	; us    <- newUniqSupply
	; state <- getState
	; let	fork_state_in = (initCgState us) 
					{ cgs_binds   = cgs_binds state,
					  cgs_stk_usg = cgs_stk_usg state,
					  cgs_hp_usg  = cgs_hp_usg state }
			-- ToDo: is the hp usage necesary?
		(code_blks, fork_state_out) = doFCode (getCgStmts body_code) 
						      info_down fork_state_in
	; setState $ state `stateIncUsageEval` fork_state_out
	; return code_blks }

codeOnly :: Code -> Code
-- Emit any code from the inner thing into the outer thing
-- Do not affect anything else in the outer state
-- Used in almost-circular code to prevent false loop dependencies
codeOnly body_code
  = do	{ info_down <- getInfoDown
	; us   <- newUniqSupply
	; state <- getState
	; let	fork_state_in = (initCgState us) { cgs_binds   = cgs_binds state,
					           cgs_stk_usg = cgs_stk_usg state,
					           cgs_hp_usg  = cgs_hp_usg state }
		((), fork_state_out) = doFCode body_code info_down fork_state_in
	; setState $ state `addCodeBlocksFrom` fork_state_out }
\end{code} @forkAlts@ $bs~d$ takes fcodes $bs$ for the branches of a @case@, and an fcode for the default case $d$, and compiles each in the current environment. The current environment is passed on unmodified, except that - the worst stack high-water mark is incorporated - the virtual Hp is moved on to the worst virtual Hp for the branches \begin{code}
forkAlts :: [FCode a] -> FCode [a]

forkAlts branch_fcodes
  = do	{ info_down <- getInfoDown
	; us <- newUniqSupply
	; state <- getState
	; let compile us branch 
		= (us2, doFCode branch info_down branch_state)
		where
		  (us1,us2) = splitUniqSupply us
	          branch_state = (initCgState us1) {
					cgs_binds   = cgs_binds state,
					cgs_stk_usg = cgs_stk_usg state,
					cgs_hp_usg  = cgs_hp_usg state }

	      (_us, results) = mapAccumL compile us branch_fcodes
	      (branch_results, branch_out_states) = unzip results
	; setState $ foldl stateIncUsage state branch_out_states
		-- NB foldl.  state is the *left* argument to stateIncUsage
	; return branch_results }
\end{code} @forkEval@ takes two blocks of code. - The first meddles with the environment to set it up as expected by the alternatives of a @case@ which does an eval (or gc-possible primop). - The second block is the code for the alternatives. (plus info for semi-tagging purposes) @forkEval@ picks up the virtual stack pointer and returns a suitable @EndOfBlockInfo@ for the caller to use, together with whatever value is returned by the second block. It uses @initEnvForAlternatives@ to initialise the environment, and @stateIncUsageAlt@ to incorporate usage; the latter ignores the heap usage. \begin{code}
forkEval :: EndOfBlockInfo              -- For the body
    	 -> Code			-- Code to set environment
	 -> FCode Sequel		-- Semi-tagging info to store
	 -> FCode EndOfBlockInfo	-- The new end of block info

forkEval body_eob_info env_code body_code
  = do  { (v, sequel) <- forkEvalHelp body_eob_info env_code body_code
 	; returnFC (EndOfBlockInfo v sequel) }

forkEvalHelp :: EndOfBlockInfo  -- For the body
    	     -> Code		-- Code to set environment
	     -> FCode a		-- The code to do after the eval
	     -> FCode (VirtualSpOffset,	-- Sp
		       a)		-- Result of the FCode
	-- A disturbingly complicated function
forkEvalHelp body_eob_info env_code body_code
  = do	{ info_down <- getInfoDown
	; us   <- newUniqSupply
	; state <- getState
	; let { info_down_for_body = info_down {cgd_eob = body_eob_info}
	      ; (_, env_state) = doFCode env_code info_down_for_body 
					 (state {cgs_uniqs = us})
	      ; state_for_body = (initCgState (cgs_uniqs env_state)) 
					{ cgs_binds   = binds_for_body,
	      				  cgs_stk_usg = stk_usg_for_body }
	      ; binds_for_body   = nukeVolatileBinds (cgs_binds env_state)
	      ; stk_usg_from_env = cgs_stk_usg env_state
	      ; virtSp_from_env  = virtSp stk_usg_from_env
	      ; stk_usg_for_body = stk_usg_from_env {realSp = virtSp_from_env,
	      					     hwSp   = virtSp_from_env}
	      ; (value_returned, state_at_end_return)
	        	= doFCode body_code info_down_for_body state_for_body		
	  } 
	; ASSERT( isNilOL (cgs_stmts state_at_end_return) )
		 -- The code coming back should consist only of nested declarations,
		 -- notably of the return vector!
	  setState $ state `stateIncUsageEval` state_at_end_return
	; return (virtSp_from_env, value_returned) }


-- ----------------------------------------------------------------------------
-- Combinators for emitting code

nopC :: Code
nopC = return ()

whenC :: Bool -> Code -> Code
whenC True  code = code
whenC False _    = nopC

-- Corresponds to 'emit' in new code generator with a smart constructor
-- from cmm/MkGraph.hs
stmtC :: CmmStmt -> Code
stmtC stmt = emitCgStmt (CgStmt stmt)

labelC :: BlockId -> Code
labelC id = emitCgStmt (CgLabel id)

newLabelC :: FCode BlockId
newLabelC = do { u <- newUnique
               ; return $ mkBlockId u }

checkedAbsC :: CmmStmt -> Code
-- Emit code, eliminating no-ops
checkedAbsC stmt = emitStmts (if isNopStmt stmt then nilOL
	 		      else unitOL stmt)

stmtsC :: [CmmStmt] -> Code
stmtsC stmts = emitStmts (toOL stmts)

-- Emit code; no no-op checking
emitStmts :: CmmStmts -> Code
emitStmts stmts = emitCgStmts (fmap CgStmt stmts)

-- forkLabelledCode is for emitting a chunk of code with a label, outside
-- of the current instruction stream.
forkLabelledCode :: Code -> FCode BlockId
forkLabelledCode code = getCgStmts code >>= forkCgStmts

emitCgStmt :: CgStmt -> Code
emitCgStmt stmt
  = do	{ state <- getState
	; setState $ state { cgs_stmts = cgs_stmts state `snocOL` stmt }
	}

emitDecl :: CmmDecl -> Code
emitDecl decl
  = do 	{ state <- getState
	; setState $ state { cgs_tops = cgs_tops state `snocOL` decl } }

emitProc :: CmmInfo -> CLabel -> [CmmFormal] -> [CmmBasicBlock] -> Code
emitProc info lbl [] blocks
  = do  { let proc_block = CmmProc info lbl (ListGraph blocks)
	; state <- getState
	; setState $ state { cgs_tops = cgs_tops state `snocOL` proc_block } }
emitProc _ _ (_:_) _ = panic "emitProc called with nonempty args"

emitSimpleProc :: CLabel -> Code -> Code
-- Emit a procedure whose body is the specified code; no info table
emitSimpleProc lbl code
  = do	{ stmts <- getCgStmts code
	; blks <- cgStmtsToBlocks stmts
	; emitProc (CmmInfo Nothing Nothing CmmNonInfoTable) lbl [] blks }

getCmm :: Code -> FCode CmmGroup
-- Get all the CmmTops (there should be no stmts)
-- Return a single Cmm which may be split from other Cmms by
-- object splitting (at a later stage)
getCmm code 
  = do	{ state1 <- getState
	; ((), state2) <- withState code (state1 { cgs_tops  = nilOL })
	; setState $ state2 { cgs_tops = cgs_tops state1 } 
        ; return (fromOL (cgs_tops state2))
        }

-- ----------------------------------------------------------------------------
-- CgStmts

-- These functions deal in terms of CgStmts, which is an abstract type
-- representing the code in the current proc.


-- emit CgStmts into the current instruction stream
emitCgStmts :: CgStmts -> Code
emitCgStmts stmts
  = do	{ state <- getState
	; setState $ state { cgs_stmts = cgs_stmts state `appOL` stmts } }

-- emit CgStmts outside the current instruction stream, and return a label
forkCgStmts :: CgStmts -> FCode BlockId
forkCgStmts stmts
  = do  { id <- newLabelC
	; emitCgStmt (CgFork id stmts)
	; return id
	}

-- turn CgStmts into [CmmBasicBlock], for making a new proc.
cgStmtsToBlocks :: CgStmts -> FCode [CmmBasicBlock]
cgStmtsToBlocks stmts
  = do  { id <- newLabelC
	; return (flattenCgStmts id stmts)
	}	

-- collect the code emitted by an FCode computation
getCgStmts' :: FCode a -> FCode (a, CgStmts)
getCgStmts' fcode
  = do	{ state1 <- getState
	; (a, state2) <- withState fcode (state1 { cgs_stmts = nilOL })
	; setState $ state2 { cgs_stmts = cgs_stmts state1  }
	; return (a, cgs_stmts state2) }

getCgStmts :: FCode a -> FCode CgStmts
getCgStmts fcode = do { (_,stmts) <- getCgStmts' fcode; return stmts }

-- Simple ways to construct CgStmts:
noCgStmts :: CgStmts
noCgStmts = nilOL

oneCgStmt :: CmmStmt -> CgStmts
oneCgStmt stmt = unitOL (CgStmt stmt)

consCgStmt :: CmmStmt -> CgStmts -> CgStmts
consCgStmt stmt stmts = CgStmt stmt `consOL` stmts

-- ----------------------------------------------------------------------------
-- Get the current module name

getModuleName :: FCode Module
getModuleName = do { info <- getInfoDown; return (cgd_mod info) }

-- ----------------------------------------------------------------------------
-- Get/set the end-of-block info

setEndOfBlockInfo :: EndOfBlockInfo -> Code -> Code
setEndOfBlockInfo eob_info code	= do
	info  <- getInfoDown
	withInfoDown code (info {cgd_eob = eob_info})

getEndOfBlockInfo :: FCode EndOfBlockInfo
getEndOfBlockInfo = do
	info <- getInfoDown
	return (cgd_eob info)

-- ----------------------------------------------------------------------------
-- Get/set the current SRT label

-- There is just one SRT for each top level binding; all the nested
-- bindings use sub-sections of this SRT.  The label is passed down to
-- the nested bindings via the monad.

getSRTLabel :: FCode CLabel	-- Used only by cgPanic
getSRTLabel = do info  <- getInfoDown
		 return (cgd_srt_lbl info)

setSRTLabel :: CLabel -> FCode a -> FCode a
setSRTLabel srt_lbl code
  = do  info <- getInfoDown
	withInfoDown code (info { cgd_srt_lbl = srt_lbl})

getSRT :: FCode SRT
getSRT = do info <- getInfoDown
            return (cgd_srt info)

setSRT :: SRT -> FCode a -> FCode a
setSRT srt code
  = do info <- getInfoDown
       withInfoDown code (info { cgd_srt = srt})

-- ----------------------------------------------------------------------------
-- Get/set the current ticky counter label

getTickyCtrLabel :: FCode CLabel
getTickyCtrLabel = do
	info <- getInfoDown
	return (cgd_ticky info)

setTickyCtrLabel :: CLabel -> Code -> Code
setTickyCtrLabel ticky code = do
	info <- getInfoDown
	withInfoDown code (info {cgd_ticky = ticky})
\end{code}