%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section[CgUpdate]{Manipulating update frames}

\begin{code}
module CgUpdate ( pushUpdateFrame, reserveSeqFrame, pushSeqFrame ) where

#include "HsVersions.h"

import CgMonad
import AbsCSyn

import CgStackery	( allocStackTop, updateFrameSize, seqFrameSize )
import CgUsages		( getVirtSp, getSpRelOffset )
import Panic		( assertPanic )
\end{code}


%********************************************************
%*							*
%*		Setting up update frames		*
%*							*
%********************************************************
\subsection[setting-update-frames]{Setting up update frames}

@pushUpdateFrame@ $updatee$ pushes a general update frame which
points to $updatee$ as the thing to be updated.  It is only used
when a thunk has just been entered, so the (real) stack pointers
are guaranteed to be nicely aligned with the top of stack.
@pushUpdateFrame@ adjusts the virtual and tail stack pointers
to reflect the frame pushed.

\begin{code}
pushUpdateFrame :: CAddrMode -> Code -> Code

pushUpdateFrame updatee code
  = 
#ifdef DEBUG
    getEndOfBlockInfo 	    	    	`thenFC` \ eob_info ->
    ASSERT(case eob_info of { EndOfBlockInfo _ (OnStack _) -> True; 
			      _ -> False})
#endif

    allocStackTop updateFrameSize	`thenFC` \ _ ->
    getVirtSp				`thenFC` \ vsp ->

    setEndOfBlockInfo (EndOfBlockInfo vsp UpdateCode) (

		-- Emit the push macro
	    absC (CMacroStmt PUSH_UPD_FRAME [
			updatee,
			int_CLit0  -- we just entered a closure, so must be zero
	    ])
	    `thenC` code
    )

int_CLit0 = mkIntCLit 0 -- out here to avoid pushUpdateFrame CAF (sigh)
\end{code}

We push a SEQ frame just before evaluating the scrutinee of a case, if
the scrutinee has a polymorphic or function type.  The SEQ frame acts
as a barrier in case the scrutinee evaluates to a partial application.

reserveSeqFrame takes the EndOfBlockInfo for the case expression and
updates the sequel to a SeqFrame, reserving room for the frame at
args_sp.  When the scrutinee comes around to pushing a return address,
it will also push the SEQ frame, using pushSeqFrame.

\begin{code}
reserveSeqFrame :: EndOfBlockInfo -> EndOfBlockInfo
reserveSeqFrame (EndOfBlockInfo args_sp (CaseAlts amode stuff)) 
  = EndOfBlockInfo (args_sp + seqFrameSize) (SeqFrame amode stuff)

pushSeqFrame :: VirtualSpOffset -> FCode VirtualSpOffset
pushSeqFrame args_sp
  = getSpRelOffset args_sp  `thenFC` \ sp_rel ->
    absC (CMacroStmt PUSH_SEQ_FRAME [CAddr sp_rel]) `thenC`
    returnFC (args_sp - seqFrameSize)
\end{code}
