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}
%************************************************************************
\begin{code}
data DataReturnConvention
= ReturnInHeap
- | ReturnInRegs [MagicId]
+ | ReturnInRegs [MagicId]
\end{code}
The register assignment given by a @ReturnInRegs@ obeys three rules:
\begin{itemize}
\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
[] -> 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}
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}
\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)
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
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...
= 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}
\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
-- 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.
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.
else Nothing
where
not_elem = isn'tIn "mkRegTbl"
-
-#endif {- Data Parallel Haskell -}
\end{code}