diff options
author | partain <unknown> | 1996-05-17 16:05:10 +0000 |
---|---|---|
committer | partain <unknown> | 1996-05-17 16:05:10 +0000 |
commit | dabfa71f33eabc5a2d10959728f772aa016f1c84 (patch) | |
tree | 927731b8c14fb245be82312436ed2c510643653b /ghc/compiler/codeGen | |
parent | f3998ec18fd0f3d56b377d41e2a2958aaf9460ec (diff) | |
download | haskell-dabfa71f33eabc5a2d10959728f772aa016f1c84.tar.gz |
[project @ 1996-05-17 16:02:43 by partain]
Sansom 1.3 changes through 960507
Diffstat (limited to 'ghc/compiler/codeGen')
-rw-r--r-- | ghc/compiler/codeGen/CgCase.lhs | 121 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgClosure.lhs | 76 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgConTbls.lhs | 26 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgExpr.lhs | 5 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgHeapery.lhs | 94 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgRetConv.lhs | 9 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgStackery.lhs | 40 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgTailCall.lhs | 12 |
8 files changed, 247 insertions, 136 deletions
diff --git a/ghc/compiler/codeGen/CgCase.lhs b/ghc/compiler/codeGen/CgCase.lhs index 85f58f16b6..2d0f3aebd1 100644 --- a/ghc/compiler/codeGen/CgCase.lhs +++ b/ghc/compiler/codeGen/CgCase.lhs @@ -30,21 +30,21 @@ import CgBindery ( getVolatileRegs, getArgAmode, getArgAmodes, idInfoToAmode ) import CgCon ( buildDynCon, bindConArgs ) -import CgHeapery ( heapCheck ) +import CgHeapery ( heapCheck, yield ) import CgRetConv ( dataReturnConvAlg, dataReturnConvPrim, ctrlReturnConvAlg, DataReturnConvention(..), CtrlReturnConvention(..), assignPrimOpResultRegs, makePrimOpArgsRobust ) -import CgStackery ( allocAStack, allocBStack ) +import CgStackery ( allocAStack, allocBStack, allocAStackTop, allocBStackTop ) import CgTailCall ( tailCallBusiness, performReturn ) import CgUsages ( getSpARelOffset, getSpBRelOffset, freeBStkSlot ) import CLabel ( mkVecTblLabel, mkReturnPtLabel, mkDefaultLabel, mkAltLabel, mkClosureLabel ) import ClosureInfo ( mkConLFInfo, mkLFArgument, layOutDynCon ) -import CmdLineOpts ( opt_SccProfilingOn ) +import CmdLineOpts ( opt_SccProfilingOn, opt_GranMacros ) import CostCentre ( useCurrentCostCentre ) import HeapOffs ( VirtualSpBOffset(..), VirtualHeapOffset(..) ) import Id ( idPrimRep, toplevelishId, @@ -55,7 +55,9 @@ import Id ( idPrimRep, toplevelishId, import Maybes ( catMaybes ) import PprStyle ( PprStyle(..) ) import PprType ( GenType{-instance Outputable-} ) -import PrimOp ( primOpCanTriggerGC, PrimOp(..) ) +import PrimOp ( primOpCanTriggerGC, PrimOp(..), + primOpStackRequired, StackRequirement(..) + ) import PrimRep ( getPrimRepSize, isFollowableRep, retPrimRepSize, PrimRep(..) ) @@ -173,10 +175,6 @@ cgCase scrut@(StgPrim op args _) live_in_whole_case live_in_alts uniq panic "cgCase: case on PrimOp with default *and* alts\n" -- For now, die if alts are non-empty else -#if 0 - pprTrace "cgCase:prim app returning alg data type: bad code!" (ppr PprDebug scrut) $ - -- See above TO DO TO DO -#endif cgExpr (StgLet (StgNonRec id scrut_rhs) deflt_rhs) where scrut_rhs = StgRhsClosure useCurrentCostCentre stgArgOcc{-safe-} scrut_free_vars @@ -199,6 +197,8 @@ cgCase (StgPrim op args _) live_in_whole_case live_in_alts uniq alts -- Perform the operation getVolatileRegs live_in_alts `thenFC` \ vol_regs -> + -- seq cannot happen here => no additional B Stack alloc + absC (COpStmt result_amodes op arg_amodes -- note: no liveness arg liveness_mask vol_regs) `thenC` @@ -231,9 +231,29 @@ cgCase (StgPrim op args _) live_in_whole_case live_in_alts uniq alts nukeDeadBindings live_in_whole_case `thenC` saveVolatileVars live_in_alts `thenFC` \ volatile_var_save_assts -> - getEndOfBlockInfo `thenFC` \ eob_info -> - forkEval eob_info nopC - (getAbsC (cgInlineAlts GCMayHappen uniq alts) `thenFC` \ abs_c -> + -- Allocate stack words for the prim-op itself, + -- these are guaranteed to be ON TOP OF the stack. + -- Currently this is used *only* by the seq# primitive op. + let + (a_req,b_req) = case (primOpStackRequired op) of + NoStackRequired -> (0, 0) + FixedStackRequired a b -> (a, b) + VariableStackRequired -> (0, 0) -- i.e. don't care + in + allocAStackTop a_req `thenFC` \ a_slot -> + allocBStackTop b_req `thenFC` \ b_slot -> + + getEndOfBlockInfo `thenFC` \ eob_info@(EndOfBlockInfo args_spa args_spb sequel) -> + -- a_req and b_req allocate stack space that is taken care of by the + -- macros generated for the primops; thus, we there is no need to adjust + -- this part of the stacks later on (=> +a_req in EndOfBlockInfo) + -- currently all this is only used for SeqOp + forkEval (if True {- a_req==0 && b_req==0 -} + then eob_info + else (EndOfBlockInfo (args_spa+a_req) + (args_spb+b_req) sequel)) nopC + ( + getAbsC (cgInlineAlts GCMayHappen uniq alts) `thenFC` \ abs_c -> absC (CRetUnVector vtbl_label (CLabelledCode return_label abs_c)) `thenC` returnFC (CaseAlts (CUnVecLbl return_label vtbl_label) @@ -461,7 +481,7 @@ cgEvalAlts cc_slot uniq (StgAlgAlts ty alts deflt) else cgSemiTaggedAlts uniq alts deflt -- Just <something> in - cgAlgAlts GCMayHappen uniq cc_restore use_labelled_alts ty alts deflt + cgAlgAlts GCMayHappen uniq cc_restore use_labelled_alts ty alts deflt True `thenFC` \ (tagged_alt_absCs, deflt_absC) -> mkReturnVector uniq ty tagged_alt_absCs deflt_absC `thenFC` \ return_vec -> @@ -493,6 +513,12 @@ cgInlineAlts :: GCFlag -> Unique -> Code \end{code} +HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): If +we do an inlining of the case no separate functions for returning are +created, so we don't have to generate a GRAN_YIELD in that case. This info +must be propagated to cgAlgAltRhs (where the GRAN_YIELD macro might be +emitted). Hence, the new Bool arg to cgAlgAltRhs. + First case: algebraic case, exactly one alternative, no default. In this case the primitive op will not have set a temporary to the tag, so we shouldn't generate a switch statment. Instead we just @@ -500,7 +526,7 @@ do the right thing. \begin{code} cgInlineAlts gc_flag uniq (StgAlgAlts ty [alt@(con,args,use_mask,rhs)] StgNoDefault) - = cgAlgAltRhs gc_flag con args use_mask rhs + = cgAlgAltRhs gc_flag con args use_mask rhs False{-no yield macro if alt gets inlined-} \end{code} Second case: algebraic case, several alternatives. @@ -509,7 +535,8 @@ Tag is held in a temporary. \begin{code} cgInlineAlts gc_flag uniq (StgAlgAlts ty alts deflt) = cgAlgAlts gc_flag uniq AbsCNop{-restore_cc-} False{-no semi-tagging-} - ty alts deflt `thenFC` \ (tagged_alts, deflt_c) -> + ty alts deflt + False{-don't emit yield-} `thenFC` \ (tagged_alts, deflt_c) -> -- Do the switch absC (mkAlgAltsCSwitch tag_amode tagged_alts deflt_c) @@ -536,6 +563,11 @@ cgInlineAlts gc_flag uniq (StgPrimAlts ty alts deflt) In @cgAlgAlts@, none of the binders in the alternatives are assumed to be yet bound. +HWL comment on {\em GrAnSim\/} (adding GRAN_YIELDs for context switch): The +last arg of cgAlgAlts indicates if we want a context switch at the +beginning of each alternative. Normally we want that. The only exception +are inlined alternatives. + \begin{code} cgAlgAlts :: GCFlag -> Unique @@ -544,6 +576,7 @@ cgAlgAlts :: GCFlag -> Type -- From the case statement -> [(Id, [Id], [Bool], StgExpr)] -- The alternatives -> StgCaseDefault -- The default + -> Bool -- Context switch at alts? -> FCode ([(ConTag, AbstractC)], -- The branches AbstractC -- The default case ) @@ -571,15 +604,16 @@ It's all pretty turgid anyway. \begin{code} cgAlgAlts gc_flag uniq restore_cc semi_tagging ty alts deflt@(StgBindDefault binder True{-used-} _) + emit_yield{-should a yield macro be emitted?-} = let extra_branches :: [FCode (ConTag, AbstractC)] extra_branches = catMaybes (map mk_extra_branch default_cons) must_label_default = semi_tagging || not (null extra_branches) in - forkAlts (map (cgAlgAlt gc_flag uniq restore_cc semi_tagging) alts) + forkAlts (map (cgAlgAlt gc_flag uniq restore_cc semi_tagging emit_yield) alts) extra_branches - (cgAlgDefault gc_flag uniq restore_cc must_label_default deflt) + (cgAlgDefault gc_flag uniq restore_cc must_label_default deflt emit_yield) where default_join_lbl = mkDefaultLabel uniq @@ -636,25 +670,36 @@ Now comes the general case \begin{code} cgAlgAlts gc_flag uniq restore_cc must_label_branches ty alts deflt {- The deflt is either StgNoDefault or a BindDefault which doesn't use the binder -} - = forkAlts (map (cgAlgAlt gc_flag uniq restore_cc must_label_branches) alts) + emit_yield{-should a yield macro be emitted?-} + + = forkAlts (map (cgAlgAlt gc_flag uniq restore_cc must_label_branches emit_yield) alts) [{- No "extra branches" -}] - (cgAlgDefault gc_flag uniq restore_cc must_label_branches deflt) + (cgAlgDefault gc_flag uniq restore_cc must_label_branches deflt emit_yield) \end{code} \begin{code} cgAlgDefault :: GCFlag -> Unique -> AbstractC -> Bool -- turgid state... -> StgCaseDefault -- input - -> FCode AbstractC -- output + -> Bool + -> FCode AbstractC -- output cgAlgDefault gc_flag uniq restore_cc must_label_branch - StgNoDefault + StgNoDefault _ = returnFC AbsCNop cgAlgDefault gc_flag uniq restore_cc must_label_branch (StgBindDefault _ False{-binder not used-} rhs) + emit_yield{-should a yield macro be emitted?-} = getAbsC (absC restore_cc `thenC` + let + emit_gran_macros = opt_GranMacros + in + (if emit_gran_macros && emit_yield + then yield [] False + else absC AbsCNop) `thenC` + -- liveness same as in possibleHeapCheck below possibleHeapCheck gc_flag [] False (cgExpr rhs)) `thenFC` \ abs_c -> let final_abs_c | must_label_branch = CJump (CLabelledCode lbl abs_c) @@ -667,11 +712,19 @@ cgAlgDefault gc_flag uniq restore_cc must_label_branch cgAlgDefault gc_flag uniq restore_cc must_label_branch (StgBindDefault binder True{-binder used-} rhs) + emit_yield{-should a yield macro be emitted?-} = -- We have arranged that Node points to the thing, even -- even if we return in registers bindNewToReg binder node mkLFArgument `thenC` getAbsC (absC restore_cc `thenC` + let + emit_gran_macros = opt_GranMacros + in + (if emit_gran_macros && emit_yield + then yield [node] False + else absC AbsCNop) `thenC` + -- liveness same as in possibleHeapCheck below possibleHeapCheck gc_flag [node] False (cgExpr rhs) -- Node is live, but doesn't need to point at the thing itself; -- it's ok for Node to point to an indirection or FETCH_ME @@ -686,15 +739,21 @@ cgAlgDefault gc_flag uniq restore_cc must_label_branch where lbl = mkDefaultLabel uniq +-- HWL comment on GrAnSim: GRAN_YIELDs needed; emitted in cgAlgAltRhs cgAlgAlt :: GCFlag -> Unique -> AbstractC -> Bool -- turgid state + -> Bool -- Context switch at alts? -> (Id, [Id], [Bool], StgExpr) -> FCode (ConTag, AbstractC) -cgAlgAlt gc_flag uniq restore_cc must_label_branch (con, args, use_mask, rhs) +cgAlgAlt gc_flag uniq restore_cc must_label_branch + emit_yield{-should a yield macro be emitted?-} + (con, args, use_mask, rhs) = getAbsC (absC restore_cc `thenC` - cgAlgAltRhs gc_flag con args use_mask rhs) `thenFC` \ abs_c -> + cgAlgAltRhs gc_flag con args use_mask rhs + emit_yield + ) `thenFC` \ abs_c -> let final_abs_c | must_label_branch = CJump (CLabelledCode lbl abs_c) | otherwise = abs_c @@ -704,9 +763,14 @@ cgAlgAlt gc_flag uniq restore_cc must_label_branch (con, args, use_mask, rhs) tag = dataConTag con lbl = mkAltLabel uniq tag -cgAlgAltRhs :: GCFlag -> Id -> [Id] -> [Bool] -> StgExpr -> Code - -cgAlgAltRhs gc_flag con args use_mask rhs +cgAlgAltRhs :: GCFlag + -> Id + -> [Id] + -> [Bool] + -> StgExpr + -> Bool -- context switch? + -> Code +cgAlgAltRhs gc_flag con args use_mask rhs emit_yield = let (live_regs, node_reqd) = case (dataReturnConvAlg con) of @@ -717,6 +781,13 @@ cgAlgAltRhs gc_flag con args use_mask rhs -- enabled only the live registers will have valid -- pointers in them. in + let + emit_gran_macros = opt_GranMacros + in + (if emit_gran_macros && emit_yield + then yield live_regs node_reqd + else absC AbsCNop) `thenC` + -- liveness same as in possibleHeapCheck below possibleHeapCheck gc_flag live_regs node_reqd ( (case gc_flag of NoGC -> mapFCs bindNewToTemp args `thenFC` \ _ -> diff --git a/ghc/compiler/codeGen/CgClosure.lhs b/ghc/compiler/codeGen/CgClosure.lhs index 54875d7fab..81ff55f65c 100644 --- a/ghc/compiler/codeGen/CgClosure.lhs +++ b/ghc/compiler/codeGen/CgClosure.lhs @@ -29,9 +29,7 @@ import CgBindery ( getCAddrMode, getArgAmodes, import CgCompInfo ( spARelToInt, spBRelToInt ) import CgUpdate ( pushUpdateFrame ) import CgHeapery ( allocDynClosure, heapCheck -#ifdef GRAN - , fetchAndReschedule -- HWL -#endif + , heapCheckOnly, fetchAndReschedule, yield -- HWL ) import CgRetConv ( mkLiveRegsMask, ctrlReturnConvAlg, dataReturnConvAlg, @@ -49,7 +47,7 @@ import CLabel ( mkClosureLabel, mkConUpdCodePtrVecLabel, mkErrorStdEntryLabel, mkRednCountsLabel ) import ClosureInfo -- lots and lots of stuff -import CmdLineOpts ( opt_EmitArityChecks, opt_ForConcurrent ) +import CmdLineOpts ( opt_ForConcurrent, opt_GranMacros ) import CostCentre ( useCurrentCostCentre, currentOrSubsumedCosts, noCostCentreAttached, costsAreSubsumed, isCafCC, overheadCostCentre @@ -432,7 +430,6 @@ closureCodeBody binder_info closure_info cc all_args body = getEntryConvention id lf_info (map idPrimRep all_args) `thenFC` \ entry_conv -> let - do_arity_chks = opt_EmitArityChecks is_concurrent = opt_ForConcurrent stg_arity = length all_args @@ -489,12 +486,6 @@ closureCodeBody binder_info closure_info cc all_args body -- Now adjust real stack pointers adjustRealSps spA_stk_args spB_stk_args `thenC` - -- set the arity checker, if asked - absC ( - if do_arity_chks - then CMacroStmt SET_ARITY [mkIntCLit stg_arity] - else AbsCNop - ) `thenC` absC (CFallThrough (CLbl fast_label CodePtrRep)) assign_to_reg reg_id amode = CAssign (CReg reg_id) amode @@ -515,11 +506,6 @@ closureCodeBody binder_info closure_info cc all_args body CString (_PK_ (show_wrapper_name wrapper_maybe)), CString (_PK_ (show_wrapper_arg_kinds wrapper_maybe)) ] `thenC` - absC ( - if do_arity_chks - then CMacroStmt CHK_ARITY [mkIntCLit stg_arity] - else AbsCNop - ) `thenC` -- Bind args to regs/stack as appropriate, and -- record expected position of sps @@ -659,35 +645,43 @@ argSatisfactionCheck closure_info args nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points -> -#ifdef GRAN - -- HWL: + let + emit_gran_macros = opt_GranMacros + in + + -- HWL ngo' ngoq: -- absC (CMacroStmt GRAN_FETCH []) `thenC` - -- forceHeapCheck [] node_points (absC AbsCNop) `thenC` - (if node_points - then fetchAndReschedule [] node_points - else absC AbsCNop) `thenC` -#endif {- GRAN -} + -- forceHeapCheck [] node_points (absC AbsCNop) `thenC` + (if emit_gran_macros + then if node_points + then fetchAndReschedule [] node_points + else yield [] node_points + else absC AbsCNop) `thenC` getCAddrMode (last args) `thenFC` \ last_amode -> if (isFollowableRep (getAmodeRep last_amode)) then getSpARelOffset 0 `thenFC` \ (SpARel spA off) -> let - lit = mkIntCLit (spARelToInt spA off) + a_rel_int = spARelToInt spA off + a_rel_arg = mkIntCLit a_rel_int in + ASSERT(a_rel_int /= 0) if node_points then - absC (CMacroStmt ARGS_CHK_A [lit]) + absC (CMacroStmt ARGS_CHK_A [a_rel_arg]) else - absC (CMacroStmt ARGS_CHK_A_LOAD_NODE [lit, set_Node_to_this]) + absC (CMacroStmt ARGS_CHK_A_LOAD_NODE [a_rel_arg, set_Node_to_this]) else getSpBRelOffset 0 `thenFC` \ (SpBRel spB off) -> let - lit = mkIntCLit (spBRelToInt spB off) + b_rel_int = spBRelToInt spB off + b_rel_arg = mkIntCLit b_rel_int in + ASSERT(b_rel_int /= 0) if node_points then - absC (CMacroStmt ARGS_CHK_B [lit]) + absC (CMacroStmt ARGS_CHK_B [b_rel_arg]) else - absC (CMacroStmt ARGS_CHK_B_LOAD_NODE [lit, set_Node_to_this]) + absC (CMacroStmt ARGS_CHK_B_LOAD_NODE [b_rel_arg, set_Node_to_this]) where -- We must tell the arg-satis macro whether Node is pointing to -- the closure or not. If it isn't so pointing, then we give to @@ -708,12 +702,16 @@ thunkWrapper closure_info thunk_code = -- Stack and heap overflow checks nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points -> -#ifdef GRAN - -- HWL insert macros for GrAnSim if node is live here - (if node_points - then fetchAndReschedule [] node_points - else absC AbsCNop) `thenC` -#endif {- GRAN -} + let + emit_gran_macros = opt_GranMacros + in + -- HWL: insert macros for GrAnSim; 2 versions depending on liveness of node + -- (we prefer fetchAndReschedule-style context switches to yield ones) + (if emit_gran_macros + then if node_points + then fetchAndReschedule [] node_points + else yield [] node_points + else absC AbsCNop) `thenC` stackCheck closure_info [] node_points ( -- stackCheck *encloses* the rest @@ -739,6 +737,14 @@ funWrapper :: ClosureInfo -- Closure whose code body this is funWrapper closure_info arg_regs fun_body = -- Stack overflow check nodeMustPointToIt (closureLFInfo closure_info) `thenFC` \ node_points -> + let + emit_gran_macros = opt_GranMacros + in + -- HWL chu' ngoq: + (if emit_gran_macros + then yield arg_regs node_points + else absC AbsCNop) `thenC` + stackCheck closure_info arg_regs node_points ( -- stackCheck *encloses* the rest -- Heap overflow check diff --git a/ghc/compiler/codeGen/CgConTbls.lhs b/ghc/compiler/codeGen/CgConTbls.lhs index 29a89a57f4..98c5a1deed 100644 --- a/ghc/compiler/codeGen/CgConTbls.lhs +++ b/ghc/compiler/codeGen/CgConTbls.lhs @@ -246,6 +246,25 @@ genConInfo comp_info tycon data_con closure_label = mkClosureLabel data_con \end{code} +The entry code for a constructor now loads the info ptr by indirecting +node. The alternative is to load the info ptr in the enter-via-node +sequence. There's is a trade-off here: + + * If the architecture can perform an indirect jump through a + register in one instruction, or if the info ptr is not a + real register, then *not* loading the info ptr on an enter + is a win. + + * If the enter-via-node code is identical whether we load the + info ptr or not, then doing it is a win (it means we don't + have to do it here). + +However, the gratuitous load here is miniscule compared to the +gratuitous loads of the info ptr on each enter, so we go for the first +option. + +-- Simon M. (6/5/96) + \begin{code} mkConCodeAndInfo :: Id -- Data constructor -> (ClosureInfo, Code) -- The info table @@ -261,7 +280,7 @@ mkConCodeAndInfo con body_code = profCtrC SLIT("RET_OLD_IN_REGS") [mkIntCLit (length regs_w_offsets)] `thenC` - performReturn (mkAbstractCs (map move_to_reg regs_w_offsets)) + performReturn (mkAbstractCs (load_infoptr : map move_to_reg regs_w_offsets)) (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-}) emptyIdSet{-no live vars-} in @@ -278,7 +297,7 @@ mkConCodeAndInfo con = -- NB: We don't set CC when entering data (WDP 94/06) profCtrC SLIT("RET_OLD_IN_HEAP") [mkIntCLit (length arg_things)] `thenC` - performReturn AbsCNop -- Ptr to thing already in Node + performReturn (mkAbstractCs [load_infoptr]) -- Ptr to thing already in Node (mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-}) emptyIdSet{-no live vars-} in @@ -288,6 +307,9 @@ mkConCodeAndInfo con move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC move_to_reg (reg, offset) = CAssign (CReg reg) (CVal (NodeRel offset) (magicIdPrimRep reg)) + + load_infoptr + = CAssign (CReg infoptr) (CMacroExpr DataPtrRep INFO_PTR [CReg node]) \end{code} %************************************************************************ diff --git a/ghc/compiler/codeGen/CgExpr.lhs b/ghc/compiler/codeGen/CgExpr.lhs index 6fed112402..dd0b7f4d4f 100644 --- a/ghc/compiler/codeGen/CgExpr.lhs +++ b/ghc/compiler/codeGen/CgExpr.lhs @@ -44,7 +44,7 @@ import PrimOp ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..), ) import PrimRep ( getPrimRepSize, PrimRep(..) ) import TyCon ( tyConDataCons ) -import Util ( panic, pprPanic ) +import Util ( panic, pprPanic, assertPanic ) \end{code} This module provides the support code for @StgToAbstractC@ to deal @@ -94,7 +94,8 @@ Here is where we insert real live machine instructions. \begin{code} cgExpr x@(StgPrim op args live_vars) - = getPrimOpArgAmodes op args `thenFC` \ arg_amodes -> + = ASSERT(op /= SeqOp) -- can't handle SeqOp + getPrimOpArgAmodes op args `thenFC` \ arg_amodes -> let result_regs = assignPrimOpResultRegs op result_amodes = map CReg result_regs diff --git a/ghc/compiler/codeGen/CgHeapery.lhs b/ghc/compiler/codeGen/CgHeapery.lhs index 798c6ba16e..fa8f1e0bdb 100644 --- a/ghc/compiler/codeGen/CgHeapery.lhs +++ b/ghc/compiler/codeGen/CgHeapery.lhs @@ -10,10 +10,8 @@ module CgHeapery ( heapCheck, allocHeap, allocDynClosure -#ifdef GRAN - -- new for GrAnSim HWL - , heapCheckOnly, fetchAndReschedule -#endif {- GRAN -} + -- new functions, basically inserting macro calls into Code -- HWL + , heapCheckOnly, fetchAndReschedule, yield ) where import Ubiq{-uitous-} @@ -41,56 +39,15 @@ import PrimRep ( PrimRep(..) ) %* * %************************************************************************ -This is std code we replaced by the bits below for GrAnSim. -- HWL +The new code for heapChecks. For GrAnSim the code for doing a heap check +and doing a context switch has been separated. Especially, the HEAP_CHK +macro only performs a heap check. THREAD_CONTEXT_SWITCH should be used for +doing a context switch. GRAN_FETCH_AND_RESCHEDULE must be put at the +beginning of every slow entry code in order to simulate the fetching of +closures. If fetching is necessary (i.e. current closure is not local) then +an automatic context switch is done. \begin{code} -#ifndef GRAN - -heapCheck :: [MagicId] -- Live registers - -> Bool -- Node reqd after GC? - -> Code - -> Code - -heapCheck regs node_reqd code - = initHeapUsage (\ hHw -> do_heap_chk hHw `thenC` code) - where - - do_heap_chk :: HeapOffset -> Code - do_heap_chk words_required - = absC (if isZeroOff(words_required) then AbsCNop else checking_code) `thenC` - -- The test is *inside* the absC, to avoid black holes! - - -- Now we have set up the real heap pointer and checked there is - -- enough space. It remains only to reflect this in the environment - - setRealHp words_required - - -- The "word_required" here is a fudge. - -- *** IT DEPENDS ON THE DIRECTION ***, and on - -- whether the Hp is moved the whole way all - -- at once or not. - where - all_regs = if node_reqd then node:regs else regs - liveness_mask = mkLiveRegsMask all_regs - - checking_code = CMacroStmt HEAP_CHK [ - mkIntCLit liveness_mask, - COffset words_required, - mkIntCLit (if node_reqd then 1 else 0)] -#endif {- GRAN -} -\end{code} - -The GrAnSim code for heapChecks. The code for doing a heap check and -doing a context switch has been separated. Especially, the HEAP_CHK -macro only performs a heap check. THREAD_CONTEXT_SWITCH should be used -for doing a context switch. GRAN_FETCH_AND_RESCHEDULE must be put at -the beginning of every slow entry code in order to simulate the -fetching of closures. If fetching is necessary (i.e. current closure -is not local) then an automatic context switch is done. - -\begin{code} -#ifdef GRAN - heapCheck :: [MagicId] -- Live registers -> Bool -- Node reqd after GC? -> Code @@ -169,10 +126,10 @@ heapCheck' do_context_switch regs node_reqd code -- Emit macro for simulating a fetch and then reschedule fetchAndReschedule :: [MagicId] -- Live registers - -> Bool -- Node reqd + -> Bool -- Node reqd? -> Code -fetchAndReschedule regs node_reqd = +fetchAndReschedule regs node_reqd = if (node `elem` regs || node_reqd) then fetch_code `thenC` reschedule_code else absC AbsCNop @@ -187,8 +144,35 @@ fetchAndReschedule regs node_reqd = --HWL: generate GRAN_FETCH macro for GrAnSim -- currently GRAN_FETCH and GRAN_FETCH_AND_RESCHEDULE are miai fetch_code = absC (CMacroStmt GRAN_FETCH []) +\end{code} + +The @GRAN_YIELD@ macro is taken from JSM's code for Concurrent Haskell. It +allows to context-switch at places where @node@ is not alive (it uses the +@Continue@ rather than the @EnterNodeCode@ function in the RTS). We emit +this kind of macro at the beginning of the following kinds of basic bocks: +\begin{itemize} + \item Slow entry code where node is not alive (see @CgClosure.lhs@). Normally + we use @fetchAndReschedule@ at a slow entry code. + \item Fast entry code (see @CgClosure.lhs@). + \item Alternatives in case expressions (@CLabelledCode@ structures), provided + that they are not inlined (see @CgCases.lhs@). These alternatives will + be turned into separate functions. +\end{itemize} + +\begin{code} +yield :: [MagicId] -- Live registers + -> Bool -- Node reqd? + -> Code + +yield regs node_reqd = + -- NB: node is not alive; that's why we use DO_YIELD rather than + -- GRAN_RESCHEDULE + yield_code + where + all_regs = if node_reqd then node:regs else regs + liveness_mask = mkLiveRegsMask all_regs -#endif {- GRAN -} + yield_code = absC (CMacroStmt GRAN_YIELD [mkIntCLit liveness_mask]) \end{code} %************************************************************************ diff --git a/ghc/compiler/codeGen/CgRetConv.lhs b/ghc/compiler/codeGen/CgRetConv.lhs index 856a119cd2..14e59f4526 100644 --- a/ghc/compiler/codeGen/CgRetConv.lhs +++ b/ghc/compiler/codeGen/CgRetConv.lhs @@ -42,7 +42,6 @@ import Id ( isDataCon, dataConSig, import Maybes ( catMaybes ) import PprStyle ( PprStyle(..) ) import PprType ( TyCon{-instance Outputable-} ) -import PrelInfo ( integerDataCon ) import PrimOp ( primOpCanTriggerGC, getPrimOpResultInfo, PrimOpResultInfo(..), PrimOp{-instance Outputable-} @@ -129,8 +128,6 @@ dataReturnConvAlg data_con (reg_assignment, leftover_kinds) = assignRegs [node, infoptr] -- taken... (map typePrimRep arg_tys) - - is_prim_result_ty = data_con == integerDataCon -- ***HACK***! (WDP 95/11) \end{code} %************************************************************************ @@ -158,7 +155,7 @@ dataReturnConvPrim ArrayRep = VanillaReg ArrayRep ILIT(1) dataReturnConvPrim ByteArrayRep = VanillaReg ByteArrayRep ILIT(1) dataReturnConvPrim StablePtrRep = VanillaReg StablePtrRep ILIT(1) -dataReturnConvPrim MallocPtrRep = VanillaReg MallocPtrRep ILIT(1) +dataReturnConvPrim ForeignObjRep = VanillaReg ForeignObjRep ILIT(1) #ifdef DEBUG dataReturnConvPrim PtrRep = panic "dataReturnConvPrim: PtrRep" @@ -207,8 +204,8 @@ argument into it). Bug: it is assumed that robust amodes cannot contain pointers. This seems reasonable but isn't true. For example, \tr{Array#}'s -\tr{MallocPtr#}'s are pointers. (This is only known to bite on -\tr{_ccall_GC_} with a MallocPtr argument.) +\tr{ForeignObj#}'s are pointers. (This is only known to bite on +\tr{_ccall_GC_} with a ForeignObj argument.) See after for some ADR comments... diff --git a/ghc/compiler/codeGen/CgStackery.lhs b/ghc/compiler/codeGen/CgStackery.lhs index 0ad6fc52fb..8e1c90a58e 100644 --- a/ghc/compiler/codeGen/CgStackery.lhs +++ b/ghc/compiler/codeGen/CgStackery.lhs @@ -10,7 +10,8 @@ Stack-twiddling operations, which are pretty low-down and grimy. #include "HsVersions.h" module CgStackery ( - allocAStack, allocBStack, allocUpdateFrame, + allocAStack, allocBStack, allocAStackTop, allocBStackTop, + allocUpdateFrame, adjustRealSps, getFinalStackHW, mkVirtStkOffsets, mkStkAmodes ) where @@ -59,7 +60,20 @@ mkVirtStkOffsets init_SpA_offset init_SpB_offset kind_fun things (last_SpA_offset, last_SpB_offset, boxd_w_offsets, ubxd_w_offsets) where computeOffset offset thing - = (offset + (getPrimRepSize . kind_fun) thing, (thing, offset+(1::Int))) + = (offset + (max 1 . getPrimRepSize . kind_fun) thing, (thing, offset+(1::Int))) + -- The "max 1" bit is ULTRA important + -- Why? mkVirtStkOffsets is the unique function that lays out function + -- arguments on the stack. The "max 1" ensures that every argument takes + -- at least one stack slot, even if it's of kind VoidKind that actually + -- takes no space at all. + -- This is important to make sure that argument satisfaction checks work + -- properly. Consider + -- f a b s# = (a,b) + -- where s# is a VoidKind. f's argument satisfaction check will check + -- that s# is on the B stack above SuB; but if s# takes zero space, the + -- check will be ARGS_B_CHK(0), which always succeeds. As a result, even + -- if a,b aren't available either, the PAP update won't trigger and + -- we are throughly hosed. (SLPJ 96/05) \end{code} @mkStackAmodes@ is a higher-level version of @mkStackOffsets@. @@ -166,6 +180,28 @@ allocBStack size info_down (MkCgState absC binds delete_block free_b slot = [s | s <- free_b, (s<slot) || (s>=slot+size)] -- Retain slots which are not in the range -- slot..slot+size-1 + +-- Allocate a chunk ON TOP OF the stack +allocAStackTop :: Int -> FCode VirtualSpAOffset +allocAStackTop size info_down (MkCgState absC binds + ((virt_a, free_a, real_a, hw_a), b_usage, h_usage)) + = (chosen_slot, MkCgState absC binds (new_a_usage, b_usage, h_usage)) + where + push_virt_a = virt_a + size + chosen_slot = virt_a + 1 + new_a_usage = (push_virt_a, free_a, real_a, hw_a `max` push_virt_a) + -- Adjust high water mark + +-- Allocate a chunk ON TOP OF the stack +allocBStackTop :: Int -> FCode VirtualSpBOffset +allocBStackTop size info_down (MkCgState absC binds + (a_usage, (virt_b, free_b, real_b, hw_b), h_usage)) + = (chosen_slot, MkCgState absC binds (a_usage, new_b_usage, h_usage)) + where + push_virt_b = virt_b + size + chosen_slot = virt_b+1 + new_b_usage = (push_virt_b, free_b, real_b, hw_b `max` push_virt_b) + -- Adjust high water mark \end{code} @allocUpdateFrame@ allocates enough space for an update frame diff --git a/ghc/compiler/codeGen/CgTailCall.lhs b/ghc/compiler/codeGen/CgTailCall.lhs index 8b3c23e5cc..15b2ae249b 100644 --- a/ghc/compiler/codeGen/CgTailCall.lhs +++ b/ghc/compiler/codeGen/CgTailCall.lhs @@ -36,7 +36,7 @@ import CLabel ( mkStdUpdCodePtrVecLabel, mkConUpdCodePtrVecLabel ) import ClosureInfo ( nodeMustPointToIt, getEntryConvention, EntryConvention(..) ) -import CmdLineOpts ( opt_EmitArityChecks, opt_DoSemiTagging ) +import CmdLineOpts ( opt_DoSemiTagging ) import HeapOffs ( zeroOff, VirtualSpAOffset(..) ) import Id ( idType, dataConTyCon, dataConTag, fIRST_TAG @@ -314,10 +314,7 @@ tailCallBusiness :: Id -> CAddrMode -- Function and its amode -> Code tailCallBusiness fun fun_amode lf_info arg_amodes live_vars pending_assts - = let - do_arity_chks = opt_EmitArityChecks - in - nodeMustPointToIt lf_info `thenFC` \ node_points -> + = nodeMustPointToIt lf_info `thenFC` \ node_points -> getEntryConvention fun lf_info (map getAmodeRep arg_amodes) `thenFC` \ entry_conv -> @@ -346,10 +343,7 @@ tailCallBusiness fun fun_amode lf_info arg_amodes live_vars pending_assts `mkAbsCStmts` CJump (CLbl lbl CodePtrRep)) DirectEntry lbl arity regs -> - (regs, (if do_arity_chks - then CMacroStmt SET_ARITY [mkIntCLit arity] - else AbsCNop) - `mkAbsCStmts` CJump (CLbl lbl CodePtrRep)) + (regs, CJump (CLbl lbl CodePtrRep)) no_of_args = length arg_amodes |