[project @ 1996-06-05 06:44:31 by partain]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgRetConv.lhs
index 9b6a130..fa36440 100644 (file)
@@ -15,40 +15,41 @@ module CgRetConv (
        ctrlReturnConvAlg,
        dataReturnConvAlg,
 
-       mkLiveRegsBitMask, noLiveRegsMask,
-
        dataReturnConvPrim,
 
        assignPrimOpResultRegs,
        makePrimOpArgsRobust,
-       assignRegs,
-
-       -- and to make the interface self-sufficient...
-       MagicId, PrimKind, Id, CLabel, TyCon
+       assignRegs
     ) where
 
-import AbsCSyn
+IMP_Ubiq(){-uitous-}
+IMPORT_DELOOPER(AbsCLoop)              -- paranoia checking
 
-import AbsPrel         ( PrimOp(..), PrimOpResultInfo(..), primOpCanTriggerGC,
-                         getPrimOpResultInfo, PrimKind
-                         IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
-                         IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import AbsCSyn         -- quite a few things
+import AbsCUtils       ( mkAbstractCs, getAmodeRep,
+                         amodeCanSurviveGC
                        )
-import AbsUniType      ( getTyConFamilySize, kindFromType, getTyConDataCons,
-                         TyVarTemplate, TyCon, Class,
-                         TauType(..), ThetaType(..), UniType
-                         IF_ATTACK_PRAGMAS(COMMA cmpTyCon COMMA cmpClass)
-                         IF_ATTACK_PRAGMAS(COMMA cmpUniType)
+import CgCompInfo      ( mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
+                         mAX_Vanilla_REG, mAX_Float_REG,
+                         mAX_Double_REG
                        )
-import CgCompInfo      -- various things
-
-import Id              ( Id, getDataConSig, fIRST_TAG, isDataCon,
-                         DataCon(..), ConTag(..)
+import CmdLineOpts     ( opt_ReturnInRegsThreshold )
+import Id              ( isDataCon, dataConRawArgTys,
+                         DataCon(..), GenId{-instance Eq-}
+                       )
+import Maybes          ( catMaybes )
+import PprStyle                ( PprStyle(..) )
+import PprType         ( TyCon{-instance Outputable-} )
+import PrimOp          ( primOpCanTriggerGC,
+                         getPrimOpResultInfo, PrimOpResultInfo(..),
+                         PrimOp{-instance Outputable-}
+                       )
+import PrimRep         ( isFloatingRep, PrimRep(..) )
+import TyCon           ( tyConDataCons, tyConFamilySize )
+import Type            ( typePrimRep )
+import Util            ( zipWithEqual, mapAccumL, isn'tIn,
+                         pprError, pprTrace, panic, assertPanic
                        )
-import Maybes          ( catMaybes, Maybe(..) )
-import PrimKind
-import Util
-import Pretty
 \end{code}
 
 %************************************************************************
@@ -69,7 +70,7 @@ data-constructor is returned.
 \begin{code}
 data DataReturnConvention
   = ReturnInHeap
-  | ReturnInRegs       [MagicId]       
+  | ReturnInRegs       [MagicId]
 \end{code}
 The register assignment given by a @ReturnInRegs@ obeys three rules:
 \begin{itemize}
@@ -88,12 +89,13 @@ The register assignment given by a @ReturnInRegs@ obeys three rules:
 
 \begin{code}
 ctrlReturnConvAlg :: TyCon -> CtrlReturnConvention
+
 ctrlReturnConvAlg tycon
-  = case (getTyConFamilySize tycon) of
-      Nothing -> -- pprPanic "ctrlReturnConvAlg:" (ppr PprDebug tycon)
-                UnvectoredReturn 0 -- e.g., w/ "data Bin"
+  = case (tyConFamilySize tycon) of
+      0 -> pprTrace "ctrlReturnConvAlg:" (ppr PprDebug tycon) $
+          UnvectoredReturn 0 -- e.g., w/ "data Bin"
 
-      Just size -> -- we're supposed to know...
+      size -> -- we're supposed to know...
        if (size > (1::Int) && size <= mAX_FAMILY_SIZE_FOR_VEC_RETURNS) then
            VectoredReturn size
        else
@@ -119,53 +121,13 @@ dataReturnConvAlg data_con
        []    ->        ReturnInRegs reg_assignment
        other ->        ReturnInHeap    -- Didn't fit in registers
   where
-    (_, _, arg_tys, _) = getDataConSig data_con
-    (reg_assignment, leftover_kinds) = assignRegs [node,infoptr] 
-                                                 (map kindFromType arg_tys)
-\end{code}
-
-\begin{code}
-noLiveRegsMask :: Int  -- Mask indicating nothing live
-noLiveRegsMask = 0
-
-mkLiveRegsBitMask
-       :: [MagicId]    -- Candidate live regs; depends what they have in them
-       -> Int
-
-mkLiveRegsBitMask regs
-  = foldl do_reg noLiveRegsMask regs
-  where
-    do_reg acc (VanillaReg kind reg_no)
-      | isFollowableKind kind
-      = acc + (reg_tbl !! IBOX(reg_no _SUB_ ILIT(1)))
+    arg_tys = dataConRawArgTys data_con
 
-    do_reg acc anything_else = acc
-
-    reg_tbl -- ToDo: mk Array!
-      = [lIVENESS_R1, lIVENESS_R2, lIVENESS_R3, lIVENESS_R4,
-        lIVENESS_R5, lIVENESS_R6, lIVENESS_R7, lIVENESS_R8]
-
-{-
--- Completely opaque code.  ADR
--- What's wrong with: (untested)
-
-mkLiveRegsBitMask regs
-  = foldl (+) noLiveRegsMask (map liveness_bit regs)
-  where
-    liveness_bit (VanillaReg kind reg_no)
-      | isFollowableKind kind
-      = reg_tbl !! (reg_no - 1)
-
-    liveness_bit anything_else 
-      = noLiveRegsBitMask
-
-    reg_tbl
-      = [lIVENESS_R1, lIVENESS_R2, lIVENESS_R3, lIVENESS_R4,
-        lIVENESS_R5, lIVENESS_R6, lIVENESS_R7, lIVENESS_R8]
--}
+    (reg_assignment, leftover_kinds)
+      = assignRegs [node, infoptr] -- taken...
+                  (map typePrimRep arg_tys)
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection[CgRetConv-prim]{Return conventions for primitive datatypes}
@@ -176,35 +138,29 @@ WARNING! If you add a return convention which can return a pointer,
 make sure you alter CgCase (cgPrimDefault) to generate the right sort
 of heap check!
 \begin{code}
-dataReturnConvPrim :: PrimKind -> MagicId
+dataReturnConvPrim :: PrimRep -> MagicId
 
-#ifndef DPH
-dataReturnConvPrim IntKind     = VanillaReg IntKind  ILIT(1)
-dataReturnConvPrim WordKind    = VanillaReg WordKind ILIT(1)
-dataReturnConvPrim AddrKind    = VanillaReg AddrKind ILIT(1)
-dataReturnConvPrim CharKind    = VanillaReg CharKind ILIT(1)
-dataReturnConvPrim FloatKind   = FloatReg  ILIT(1)
-dataReturnConvPrim DoubleKind  = DoubleReg ILIT(1)
-dataReturnConvPrim VoidKind    = VoidReg
+dataReturnConvPrim IntRep      = VanillaReg IntRep  ILIT(1)
+dataReturnConvPrim WordRep     = VanillaReg WordRep ILIT(1)
+dataReturnConvPrim AddrRep     = VanillaReg AddrRep ILIT(1)
+dataReturnConvPrim CharRep     = VanillaReg CharRep ILIT(1)
+dataReturnConvPrim FloatRep    = FloatReg  ILIT(1)
+dataReturnConvPrim DoubleRep   = DoubleReg ILIT(1)
+dataReturnConvPrim VoidRep     = VoidReg
 
 -- Return a primitive-array pointer in the usual register:
-dataReturnConvPrim ArrayKind     = VanillaReg ArrayKind ILIT(1)
-dataReturnConvPrim ByteArrayKind = VanillaReg ByteArrayKind ILIT(1)
+dataReturnConvPrim ArrayRep     = VanillaReg ArrayRep ILIT(1)
+dataReturnConvPrim ByteArrayRep = VanillaReg ByteArrayRep ILIT(1)
 
-dataReturnConvPrim StablePtrKind = VanillaReg StablePtrKind ILIT(1)
-dataReturnConvPrim MallocPtrKind = VanillaReg MallocPtrKind ILIT(1)
+dataReturnConvPrim StablePtrRep = VanillaReg StablePtrRep ILIT(1)
+dataReturnConvPrim ForeignObjRep = VanillaReg ForeignObjRep ILIT(1)
 
-dataReturnConvPrim PtrKind     = panic "dataReturnConvPrim: PtrKind"
+#ifdef DEBUG
+dataReturnConvPrim PtrRep      = panic "dataReturnConvPrim: PtrRep"
 dataReturnConvPrim _           = panic "dataReturnConvPrim: other"
-
-#else
-dataReturnConvPrim VoidKind    = VoidReg
-dataReturnConvPrim PtrKind     = panic "dataReturnConvPrim: PtrKind"
-dataReturnConvPrim kind         = DataReg kind 2 -- Don't Hog a Modifier reg.
-#endif {- Data Parallel Haskell -}
+#endif
 \end{code}
 
-
 %********************************************************
 %*                                                     *
 \subsection[primop-stuff]{Argument and return conventions for Prim Ops}
@@ -213,7 +169,7 @@ dataReturnConvPrim kind         = DataReg kind 2 -- Don't Hog a Modifier reg.
 
 \begin{code}
 assignPrimOpResultRegs
-    :: PrimOp  -- The constructors in canonical order
+    :: PrimOp          -- The constructors in canonical order
     -> [MagicId]       -- The return regs all concatenated to together,
                        -- (*including* one for the tag if necy)
 
@@ -222,18 +178,20 @@ assignPrimOpResultRegs op
 
        ReturnsPrim kind -> [dataReturnConvPrim kind]
 
-       ReturnsAlg tycon -> let cons        = getTyConDataCons tycon
-                               result_regs = concat (map get_return_regs cons)
-                           in
-                               -- Since R1 is dead, it can hold the tag if necessary
-                           case cons of
-                               [_]   -> result_regs
-                               other -> (VanillaReg IntKind ILIT(1)) : result_regs
-
- where
-   get_return_regs con = case (dataReturnConvAlg con) of
-                             ReturnInHeap      -> panic "getPrimOpAlgResultRegs"
-                             ReturnInRegs regs -> regs
+       ReturnsAlg tycon
+         -> let
+               cons        = tyConDataCons tycon
+               result_regs = concat (map get_return_regs cons)
+            in
+            -- As R1 is dead, it can hold the tag if necessary
+            case cons of
+               [_]   -> result_regs
+               other -> (VanillaReg IntRep ILIT(1)) : result_regs
+  where
+    get_return_regs con
+      = case (dataReturnConvAlg con) of
+         ReturnInRegs regs -> regs
+         ReturnInHeap      -> panic "getPrimOpAlgResultRegs"
 \end{code}
 
 @assignPrimOpArgsRobust@ is used only for primitive ops which may
@@ -244,8 +202,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...
 
@@ -261,24 +219,27 @@ makePrimOpArgsRobust op arg_amodes
   = ASSERT (primOpCanTriggerGC op)
     let
        non_robust_amodes = filter (not . amodeCanSurviveGC) arg_amodes
-       arg_kinds = map getAmodeKind non_robust_amodes
+       arg_kinds = map getAmodeRep non_robust_amodes
 
-       (arg_regs, extra_args) = assignRegs [{-nothing live-}] arg_kinds
+       (arg_regs, extra_args)
+         = assignRegs [{-nothing live-}] arg_kinds
 
                -- Check that all the args fit before returning arg_regs
        final_arg_regs = case extra_args of
                           []    -> arg_regs
-                          other -> error ("Cannot allocate enough registers for primop (try rearranging code or reducing number of arguments?) " ++ ppShow 80 (ppr PprDebug op))
+                          other -> pprError "Cannot allocate enough registers for primop (try rearranging code or reducing number of arguments?)" (ppr PprDebug op)
+
+       arg_assts
+         = mkAbstractCs (zipWithEqual "assign_to_reg" assign_to_reg final_arg_regs non_robust_amodes)
 
-       arg_assts = mkAbstractCs (zipWith assign_to_reg arg_regs non_robust_amodes)
        assign_to_reg reg_id amode = CAssign (CReg reg_id) amode
 
-       safe_arg regs arg 
-               | amodeCanSurviveGC arg = (regs, arg) 
+       safe_arg regs arg
+               | amodeCanSurviveGC arg = (regs, arg)
                | otherwise             = (tail regs, CReg (head regs))
-       safe_amodes = snd (mapAccumL safe_arg arg_regs arg_amodes)
+       safe_amodes = snd (mapAccumL safe_arg final_arg_regs arg_amodes)
 
-       liveness_mask = mkLiveRegsBitMask arg_regs
+       liveness_mask = mkLiveRegsMask final_arg_regs
     in
     (safe_amodes, liveness_mask, arg_assts)
 \end{code}
@@ -298,33 +259,32 @@ register); we just return immediately with the left-overs specified.
 
 \begin{code}
 assignRegs  :: [MagicId]       -- Unavailable registers
-           -> [PrimKind]       -- Arg or result kinds to assign
+           -> [PrimRep]        -- Arg or result kinds to assign
            -> ([MagicId],      -- Register assignment in same order
                                -- for *initial segment of* input list
-               [PrimKind])-- leftover kinds
+               [PrimRep])-- leftover kinds
 
-#ifndef DPH
 assignRegs regs_in_use kinds
  = assign_reg kinds [] (mkRegTbl regs_in_use)
  where
 
-    assign_reg :: [PrimKind]  -- arg kinds being scrutinized
+    assign_reg :: [PrimRep]  -- arg kinds being scrutinized
                -> [MagicId]        -- accum. regs assigned so far (reversed)
                -> ([Int], [Int], [Int])
                        -- regs still avail: Vanilla, Float, Double
-               -> ([MagicId], [PrimKind])
+               -> ([MagicId], [PrimRep])
 
-    assign_reg (VoidKind:ks) acc supply
+    assign_reg (VoidRep:ks) acc supply
        = assign_reg ks (VoidReg:acc) supply -- one VoidReg is enough for everybody!
 
-    assign_reg (FloatKind:ks) acc (vanilla_rs, IBOX(f):float_rs, double_rs)
+    assign_reg (FloatRep:ks) acc (vanilla_rs, IBOX(f):float_rs, double_rs)
        = assign_reg ks (FloatReg f:acc) (vanilla_rs, float_rs, double_rs)
 
-    assign_reg (DoubleKind:ks) acc (vanilla_rs, float_rs, IBOX(d):double_rs)
+    assign_reg (DoubleRep:ks) acc (vanilla_rs, float_rs, IBOX(d):double_rs)
        = assign_reg ks (DoubleReg d:acc) (vanilla_rs, float_rs, double_rs)
 
     assign_reg (k:ks) acc (IBOX(v):vanilla_rs, float_rs, double_rs)
-       | not (isFloatingKind k)
+       | not (isFloatingRep k)
        = assign_reg ks (VanillaReg k v:acc) (vanilla_rs, float_rs, double_rs)
 
     -- The catch-all.  It can happen because either
@@ -333,53 +293,6 @@ assignRegs regs_in_use kinds
     --  or, I suppose,
     --  (c) we came across a Kind we couldn't handle (this one shouldn't happen)
     assign_reg leftover_ks acc _ = (reverse acc, leftover_ks)
-#else
-assignRegs node_using_Ret1 kinds
- = if node_using_Ret1
-   then assign_reg kinds [] (tail vanillaRegNos) (tail datRegNos)
-   else assign_reg kinds [] vanillaRegNos        (tail datRegNos)
- where
-    assign_reg:: [PrimKind]  -- arg kinds being scrutinized
-             -> [MagicId]        -- accum. regs assigned so far (reversed)
-             -> [Int]     -- Vanilla Regs (ptr, int, char, float or double)
-             -> [Int]     -- Data Regs    (     int, char, float or double)
-             -> ([MagicId], [PrimKind])
-
-    assign_reg (k:ks) acc (IBOX(p):ptr_regs) dat_regs
-      | isFollowableKind k      
-      = assign_reg ks (VanillaReg k p:acc) ptr_regs dat_regs
-
-    assign_reg (CharKind:ks) acc ptr_regs (d:dat_regs)
-      = assign_reg ks (DataReg CharKind d:acc) ptr_regs dat_regs
-
-    assign_reg (IntKind:ks) acc ptr_regs (d:dat_regs)
-      = assign_reg ks (DataReg IntKind d:acc) ptr_regs dat_regs
-
-    assign_reg (WordKind:ks) acc ptr_regs (d:dat_regs)
-      = assign_reg ks (DataReg WordKind d:acc) ptr_regs dat_regs
-
-    assign_reg (AddrKind:ks) acc ptr_regs (d:dat_regs)
-      = assign_reg ks (DataReg AddrKind d:acc) ptr_regs dat_regs
-
-    assign_reg (FloatKind:ks) acc ptr_regs (d:dat_regs)
-      = assign_reg ks (DataReg FloatKind d:acc) ptr_regs dat_regs
-
-    -- Notice how doubles take up two data registers....
-    assign_reg (DoubleKind:ks)   acc ptr_regs (IBOX(d1):d2:dat_regs)
-      = assign_reg ks (DoubleReg d1:acc) ptr_regs dat_regs
-
-    assign_reg (VoidKind:ks) acc ptr_regs dat_regs
-      = assign_reg ks (VoidReg:acc) ptr_regs dat_regs
-
-    -- The catch-all.  It can happen because either
-    -- (a) we've assigned all the regs so leftover_ks is []
-    --  (b) we couldn't find a spare register in the appropriate supply
-    --  or, I suppose,
-    --  (c) we came across a Kind we couldn't handle (this one shouldn't happen)
-    --  ToDo Maybe when dataReg becomes empty, we can start using the
-    --       vanilla registers ????
-    assign_reg leftover_ks acc _ _ = (reverse acc, leftover_ks)
-#endif {- Data Parallel Haskell -}
 \end{code}
 
 Register supplies.  Vanilla registers can contain pointers, Ints, Chars.
@@ -389,35 +302,28 @@ vanillaRegNos :: [Int]
 vanillaRegNos  = [1 .. mAX_Vanilla_REG]
 \end{code}
 
-Only a subset of the registers on the DAP can be used to hold pointers (and most
-of these are taken up with things like the heap pointer and stack pointers). 
-However the resulting registers can hold integers, floats or chars. We therefore
-allocate pointer like things into the @vanillaRegNos@ (and Ints Chars or Floats
-if the remaining registers are empty). See NOTE.regsiterMap for an outline of
-the global and local register allocation scheme.
-
-\begin{code}
-#ifdef DPH
-datRegNos ::[Int]              
-datRegNos = [1..mAX_Data_REG]          -- For Ints, Floats, Doubles or Chars
-#endif {- Data Parallel Haskell -}
-\end{code}
-
 Floats and doubles have separate register supplies.
 
 \begin{code}
-#ifndef DPH
 floatRegNos, doubleRegNos :: [Int]
 floatRegNos    = [1 .. mAX_Float_REG]
 doubleRegNos   = [1 .. mAX_Double_REG]
 
 mkRegTbl :: [MagicId] -> ([Int], [Int], [Int])
-mkRegTbl regs_in_use = (ok_vanilla, ok_float, ok_double)
+
+mkRegTbl regs_in_use
+  = (ok_vanilla, ok_float, ok_double)
   where
-    ok_vanilla = catMaybes (map (select (VanillaReg VoidKind)) vanillaRegNos)
+    ok_vanilla = catMaybes (map (select (VanillaReg VoidRep)) (taker vanillaRegNos))
     ok_float   = catMaybes (map (select FloatReg)             floatRegNos)
     ok_double  = catMaybes (map (select DoubleReg)            doubleRegNos)
 
+    taker :: [Int] -> [Int]
+    taker rs
+      = case (opt_ReturnInRegsThreshold) of
+         Nothing -> rs -- no flag set; use all of them
+         Just  n -> take n rs
+
     select :: (FAST_INT -> MagicId) -> Int{-cand-} -> Maybe Int
        -- one we've unboxed the Int, we make a MagicId
        -- and see if it is already in use; if not, return its number.
@@ -431,6 +337,4 @@ mkRegTbl regs_in_use = (ok_vanilla, ok_float, ok_double)
        else Nothing
       where
        not_elem = isn'tIn "mkRegTbl"
-
-#endif {- Data Parallel Haskell -}
 \end{code}