%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
-% $Id: CgTailCall.lhs,v 1.16 1998/12/02 13:17:52 simonm Exp $
+% $Id: CgTailCall.lhs,v 1.26 2000/07/14 08:14:53 simonpj Exp $
%
%********************************************************
%* *
import CgMonad
import AbsCSyn
+import PprAbsC ( pprAmode )
-import AbsCUtils ( mkAbstractCs, mkAbsCStmts, getAmodeRep )
+import AbsCUtils ( mkAbstractCs, getAmodeRep )
import CgBindery ( getArgAmodes, getCAddrMode, getCAddrModeAndInfo )
import CgRetConv ( dataReturnConvPrim,
ctrlReturnConvAlg, CtrlReturnConvention(..),
assignAllRegs, assignRegs
)
-import CgStackery ( adjustRealSp, mkTaggedStkAmodes, adjustStackHW )
-import CgUsages ( getSpRelOffset )
+import CgStackery ( mkTaggedStkAmodes, adjustStackHW )
+import CgUsages ( getSpRelOffset, adjustSpAndHp )
import CgUpdate ( pushSeqFrame )
-import CLabel ( mkUpdEntryLabel, mkRtsPrimOpLabel )
+import CLabel ( mkUpdInfoLabel, mkRtsPrimOpLabel,
+ mkBlackHoleInfoTableLabel )
import ClosureInfo ( nodeMustPointToIt,
getEntryConvention, EntryConvention(..),
LambdaFormInfo
import CmdLineOpts ( opt_DoSemiTagging )
import Id ( Id, idType, idName )
import DataCon ( DataCon, dataConTyCon, dataConTag, fIRST_TAG )
-import Const ( mkMachInt )
-import Maybes ( assocMaybe )
+import Maybes ( assocMaybe, maybeToBool )
import PrimRep ( PrimRep(..) )
import StgSyn ( StgArg, GenStgArg(..) )
import Type ( isUnLiftedType )
import TyCon ( TyCon )
import PrimOp ( PrimOp )
-import Util ( zipWithEqual, panic, assertPanic )
+import Util ( zipWithEqual )
+import Unique ( mkPseudoUnique1 )
+import Outputable
+import Panic ( panic, assertPanic )
\end{code}
%************************************************************************
cgTailCall fun []
| isUnLiftedType (idType fun)
= getCAddrMode fun `thenFC` \ amode ->
- performPrimReturn amode
+ performPrimReturn (ppr fun) amode
\end{code}
The general case (@fun@ is boxed):
%************************************************************************
\begin{code}
-performPrimReturn :: CAddrMode -- The thing to return
+performPrimReturn :: SDoc -- Just for debugging (sigh)
+ -> CAddrMode -- The thing to return
-> Code
-performPrimReturn amode
+performPrimReturn doc amode
= let
kind = getAmodeRep amode
- ret_reg = dataReturnConvPrim kind
+ ret_reg = WARN( case kind of { PtrRep -> True; other -> False }, text "primRet" <+> doc <+> pprAmode amode )
+ dataReturnConvPrim kind
assign_possibly = case kind of
VoidRep -> AbsCNop
kind -> (CAssign (CReg ret_reg) amode)
in
- performReturn assign_possibly mkPrimReturnCode
+ performReturn assign_possibly (mkPrimReturnCode doc)
-mkPrimReturnCode :: Sequel -> Code
-mkPrimReturnCode UpdateCode = panic "mkPrimReturnCode: Upd"
-mkPrimReturnCode sequel = sequelToAmode sequel `thenFC` \ dest_amode ->
+mkPrimReturnCode :: SDoc -- Debugging only
+ -> Sequel
+ -> Code
+mkPrimReturnCode doc UpdateCode = pprPanic "mkPrimReturnCode: Upd" doc
+mkPrimReturnCode doc sequel = sequelToAmode sequel `thenFC` \ dest_amode ->
absC (CReturn dest_amode DirectReturn)
-- Direct, no vectoring
UpdateCode -> -- Ha! We can go direct to the update code,
-- (making sure to jump to the *correct* update
-- code.)
- absC (CReturn (CLbl mkUpdEntryLabel CodePtrRep)
+ absC (CReturn (CLbl mkUpdInfoLabel CodePtrRep)
return_info)
CaseAlts _ (Just (alts, _)) -> -- Ho! We know the constructor so
-- stack location)
pushReturnAddress eob `thenC`
- -- Adjust stack pointer
- adjustRealSp args_sp `thenC`
+ -- Adjust Sp/Hp
+ adjustSpAndHp args_sp `thenC`
-- Do the return
finish_code sequel -- "sequel" is `robust' in that it doesn't
pushReturnAddress eob `thenC`
setEndOfBlockInfo (EndOfBlockInfo args_sp (OnStack args_sp)) (
- -- Adjust stack pointer
- adjustRealSp args_sp `thenC`
+ -- Adjust Sp/Hp
+ adjustSpAndHp args_sp `thenC`
before_jump `thenC`
let (ret_regs, leftovers) = assignRegs [] (map getAmodeRep amodes)
in
+ profCtrC SLIT("TICK_RET_UNBOXED_TUP") [mkIntCLit (length amodes)] `thenC`
+
doTailCall amodes ret_regs
mkUnboxedTupleReturnCode
(length leftovers) {- fast args arity -}
-> (Sequel->Code) -- code to perform jump
-> Int -- number of "fast" stack arguments
-> AbstractC -- pending assignments
- -> Maybe VirtualSpOffset -- sp offset to trim stack to
+ -> Maybe VirtualSpOffset -- sp offset to trim stack to:
+ -- USED iff destination is a let-no-escape
-> Bool -- node points to the closure to enter
-> Code
= getEndOfBlockInfo `thenFC` \ eob@(EndOfBlockInfo args_sp sequel) ->
let
- no_of_args = length arg_amodes
-
(reg_arg_amodes, stk_arg_amodes) = splitAt (length arg_regs) arg_amodes
-- We get some stk_arg_amodes if (a) no regs, or
-- (b) args beyond arity
(fast_stk_amodes, tagged_stk_amodes) =
splitAt arity stk_arg_amodes
+
+ -- eager blackholing, at the end of the basic block.
+ (r1_tmp_asst, bh_asst)
+ = case sequel of
+#if 0
+ -- no: UpdateCode doesn't tell us that we're in a thunk's entry code.
+ -- we might be in a case continuation later down the line. Also,
+ -- we might have pushed a return address on the stack, if we're in
+ -- a case scrut, and still be in the thunk's entry code.
+ UpdateCode ->
+ (CAssign node_save nodeReg,
+ CAssign (CVal (CIndex node_save (mkIntCLit 0) PtrRep)
+ PtrRep)
+ (CLbl mkBlackHoleInfoTableLabel DataPtrRep))
+ where
+ node_save = CTemp (mkPseudoUnique1 2) DataPtrRep
+#endif
+ _ -> (AbsCNop, AbsCNop)
in
-- We can omit tags on the arguments passed to the fast entry point,
-- but we have to be careful to fill in the tags on any *extra*
-- The stack space for the pushed return addess,
-- with any args pushed on top, is recorded in final_sp.
- -- Do the simultaneous assignments,
- doSimAssts (mkAbstractCs [pending_assts,
+ -- Do the simultaneous assignments,
+ doSimAssts (mkAbstractCs [r1_tmp_asst,
+ pending_assts,
reg_arg_assts,
fast_arg_assts,
tagged_arg_assts,
tag_assts]) `thenC`
+ absC bh_asst `thenC`
-- push a return address if necessary
-- (after the assignments above, in case we clobber a live
-- stack location)
- pushReturnAddress eob `thenC`
- -- Final adjustment of stack pointer
- adjustRealSp final_sp `thenC`
+ -- DONT push the return address when we're about
+ -- to jump to a let-no-escape: the final tail call
+ -- in the let-no-escape will do this.
+ (if (maybeToBool maybe_join_sp)
+ then nopC
+ else pushReturnAddress eob) `thenC`
+
+ -- Final adjustment of Sp/Hp
+ adjustSpAndHp final_sp `thenC`
-- Now decide about semi-tagging
let