[project @ 1996-06-05 06:44:31 by partain]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgHeapery.lhs
index 226ff6b..888908f 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
 %
 \section[CgHeapery]{Heap management functions}
 
@@ -8,30 +8,29 @@
 
 module CgHeapery (
        heapCheck,
-       allocHeap, allocDynClosure,
+       allocHeap, allocDynClosure
 
-#ifdef GRAN
-        -- new for GrAnSim    HWL
-       heapCheckOnly, fetchAndReschedule,
-#endif  {- GRAN -}
-
-       -- and to make the interface self-sufficient...
-       AbstractC, CAddrMode, HeapOffset,
-       CgState, ClosureInfo, Id
+        -- new functions, basically inserting macro calls into Code -- HWL
+        , heapCheckOnly, fetchAndReschedule, yield
     ) where
 
+IMP_Ubiq(){-uitous-}
+
 import AbsCSyn
 import CgMonad
 
-import CgRetConv       ( mkLiveRegsBitMask )
+import AbsCUtils       ( mkAbstractCs, getAmodeRep )
+import CgRetConv       ( mkLiveRegsMask )
 import CgUsages                ( getVirtAndRealHp, setVirtHp, setRealHp,
                          initHeapUsage
                        )
-import ClosureInfo     ( closureSize, closureHdrSize, closureGoodStuffSize, slopSize,
-                         layOutDynClosure,
-                         allocProfilingMsg, closureKind
+import ClosureInfo     ( closureSize, closureHdrSize, closureGoodStuffSize,
+                         slopSize, allocProfilingMsg, closureKind
                        )
-import Util
+import HeapOffs                ( isZeroOff, addOff, intOff,
+                         VirtualHeapOffset(..)
+                       )
+import PrimRep         ( PrimRep(..) )
 \end{code}
 
 %************************************************************************
@@ -40,23 +39,61 @@ import Util
 %*                                                                     *
 %************************************************************************
 
-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 
+heapCheck :: [MagicId]          -- Live registers
+         -> Bool               -- Node reqd after GC?
+         -> Code
          -> Code
 
-heapCheck regs node_reqd code
+heapCheck = heapCheck' False
+
+heapCheckOnly :: [MagicId]          -- Live registers
+                -> Bool               -- Node reqd after GC?
+                -> Code
+                -> Code
+
+heapCheckOnly = heapCheck' False
+
+-- May be emit context switch and emit heap check macro
+
+heapCheck' ::   Bool                    -- context switch here?
+               -> [MagicId]            -- Live registers
+               -> Bool                 -- Node reqd after GC?
+               -> Code
+               -> Code
+
+heapCheck' do_context_switch 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`
+      =
+       -- HWL:: absC (CComment "Forced heap check --- HWL")  `thenC`
+       --absC  (if do_context_switch
+       --         then context_switch_code
+       --         else AbsCNop)                                 `thenC`
+
+       absC (if do_context_switch && not (isZeroOff words_required)
+               then context_switch_code
+               else AbsCNop)                                   `thenC`
+       absC (if isZeroOff(words_required)
+               then  AbsCNop
+               else  checking_code)  `thenC`
+
+       -- HWL was here:
+       --  For GrAnSim we want heap checks even if no heap is allocated in
+       --  the basic block to make context switches possible.
+       --  So, the if construct has been replaced by its else branch.
+
            -- The test is *inside* the absC, to avoid black holes!
 
        -- Now we have set up the real heap pointer and checked there is
@@ -70,124 +107,72 @@ heapCheck regs node_reqd code
            -- at once or not.
       where
        all_regs = if node_reqd then node:regs else regs
-       liveness_mask = mkLiveRegsBitMask all_regs
+       liveness_mask = mkLiveRegsMask all_regs
+
+       maybe_context_switch = if do_context_switch
+                               then context_switch_code
+                               else AbsCNop
 
+       context_switch_code = CMacroStmt THREAD_CONTEXT_SWITCH [
+                             mkIntCLit liveness_mask,
+                             mkIntCLit (if node_reqd then 1 else 0)]
+
+       -- Good old heap check (excluding context switch)
        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 
-          -> Code
-
-heapCheck = heapCheck' False
-
-heapCheckOnly :: [MagicId]          -- Live registers
-                 -> Bool               -- Node reqd after GC?
-                 -> Code 
-                 -> Code
-
-heapCheckOnly = heapCheck' False
-
--- May be emit context switch and emit heap check macro 
-
-heapCheck' ::   Bool                    -- context switch here?
-                -> [MagicId]            -- Live registers
-                -> Bool                 -- Node reqd after GC?
-                -> Code 
-                -> Code
-
-heapCheck' do_context_switch regs node_reqd code
-  = initHeapUsage (\ hHw -> do_heap_chk hHw `thenC` code)
-  where
-
-    do_heap_chk :: HeapOffset -> Code
-    do_heap_chk words_required
-      =         
-        -- HWL:: absC (CComment "Forced heap check --- HWL")  `thenC`
-        --absC  (if do_context_switch 
-        --         then context_switch_code
-        --         else AbsCNop)                                 `thenC`
-
-        absC (if do_context_switch && not (isZeroOff words_required)
-                then context_switch_code
-                else AbsCNop)                                   `thenC`
-        absC (if isZeroOff(words_required)
-                then  AbsCNop 
-                else  checking_code)  `thenC`
-
-        -- HWL was here:
-        --  For GrAnSim we want heap checks even if no heap is allocated in 
-        --  the basic block to make context switches possible.
-        --  So, the if construct has been replaced by its else branch.
-
-            -- 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 = mkLiveRegsBitMask all_regs
-
-        maybe_context_switch = if do_context_switch
-                                then context_switch_code
-                                else AbsCNop
-
-        context_switch_code = CMacroStmt THREAD_CONTEXT_SWITCH [
-                              mkIntCLit liveness_mask,
-                              mkIntCLit (if node_reqd then 1 else 0)]
-
-        -- Good old heap check (excluding context switch)
-        checking_code = CMacroStmt HEAP_CHK [
-                        mkIntCLit liveness_mask,
-                        COffset words_required,
-                        mkIntCLit (if node_reqd then 1 else 0)]
+                       mkIntCLit (if node_reqd then 1 else 0)]
 
 -- Emit macro for simulating a fetch and then reschedule
 
 fetchAndReschedule ::   [MagicId]               -- Live registers
-                        -> Bool                 -- Node reqd
-                        -> Code 
+                       -> 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
       where
-        all_regs = if node_reqd then node:regs else regs
-        liveness_mask = mkLiveRegsBitMask all_regs
+       all_regs = if node_reqd then node:regs else regs
+       liveness_mask = mkLiveRegsMask all_regs
 
-        reschedule_code = absC  (CMacroStmt GRAN_RESCHEDULE [
-                                 mkIntCLit liveness_mask,
-                                 mkIntCLit (if node_reqd then 1 else 0)])
+       reschedule_code = absC  (CMacroStmt GRAN_RESCHEDULE [
+                                mkIntCLit liveness_mask,
+                                mkIntCLit (if node_reqd then 1 else 0)])
 
-         --HWL: generate GRAN_FETCH macro for GrAnSim 
-         --     currently GRAN_FETCH and GRAN_FETCH_AND_RESCHEDULE are miai
-        fetch_code = absC (CMacroStmt GRAN_FETCH [])
+        --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}
 
 %************************************************************************
@@ -219,10 +204,10 @@ allocDynClosure closure_info use_cc blame_cc amodes_with_offsets
     let  info_offset = addOff virtHp (intOff 1)
 
        -- do_move IS THE ASSIGNMENT FUNCTION
-         do_move (amode, offset_from_start)
+        do_move (amode, offset_from_start)
           = CAssign (CVal (HpRel realHp
                                  (info_offset `addOff` offset_from_start))
-                          (getAmodeKind amode))
+                          (getAmodeRep amode))
                     amode
     in
        -- SAY WHAT WE ARE ABOUT TO DO
@@ -240,7 +225,7 @@ allocDynClosure closure_info use_cc blame_cc amodes_with_offsets
        -- GENERATE CC PROFILING MESSAGES
     costCentresC SLIT("CC_ALLOC") [blame_cc,
                             COffset closure_size,
-                            CLitLit (_PK_ (closureKind closure_info)) IntKind]
+                            CLitLit (_PK_ (closureKind closure_info)) IntRep]
                                                        `thenC`
 
        -- BUMP THE VIRTUAL HEAP POINTER