summaryrefslogtreecommitdiff
path: root/ghc/compiler/absCSyn/HeapOffs.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/absCSyn/HeapOffs.lhs')
-rw-r--r--ghc/compiler/absCSyn/HeapOffs.lhs402
1 files changed, 402 insertions, 0 deletions
diff --git a/ghc/compiler/absCSyn/HeapOffs.lhs b/ghc/compiler/absCSyn/HeapOffs.lhs
new file mode 100644
index 0000000000..79000d9043
--- /dev/null
+++ b/ghc/compiler/absCSyn/HeapOffs.lhs
@@ -0,0 +1,402 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[HeapOffs]{Abstract C: heap offsets}
+
+Part of ``Abstract C.'' Heap offsets---main point: they are {\em
+symbolic}---are sufficiently turgid that they get their own module.
+
+INTERNAL MODULE: should be accessed via @AbsCSyn.hi@.
+
+\begin{code}
+#include "HsVersions.h"
+
+module HeapOffs (
+#ifndef DPH
+ HeapOffset,
+#else
+ HeapOffset(..), -- DPH needs to do a little peaking inside this thing.
+#endif {- Data Parallel Haskell -}
+
+ zeroOff, intOff, fixedHdrSize, totHdrSize, varHdrSize,
+ maxOff, addOff, subOff,
+ isZeroOff, possiblyEqualHeapOffset,
+
+ pprHeapOffset,
+
+ intOffsetIntoGoods,
+
+#if ! OMIT_NATIVE_CODEGEN
+ hpRelToInt,
+#endif
+
+ VirtualHeapOffset(..), HpRelOffset(..),
+ VirtualSpAOffset(..), VirtualSpBOffset(..),
+ SpARelOffset(..), SpBRelOffset(..)
+ ) where
+
+import ClosureInfo -- esp. about SMReps
+import SMRep
+#if ! OMIT_NATIVE_CODEGEN
+import MachDesc
+#endif
+import Maybes ( catMaybes, Maybe(..) )
+import Outputable
+import Unpretty -- ********** NOTE **********
+import Util
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[Offsets-Heap-and-others]{Offsets, Heap and otherwise}
+%* *
+%************************************************************************
+
+\begin{code}
+{-
+ < fixed-hdr-size> < var-hdr-size >
+ ---------------------------------------------------------------------
+ |info| | | | | | | | ptrs... | nonptrs ... | slop.... |
+ ---------------------------------------------------------------------
+ <------------- header ------------>
+
+ * Node, the ptr to the closure, pts at its info-ptr field
+-}
+data HeapOffset
+ = MkHeapOffset
+
+ FAST_INT -- this many words...
+
+ FAST_INT -- PLUS: this many FixedHdrSizes
+
+ [SMRep__Int] -- PLUS: for each elem in this list:
+ -- "Int" VarHdrSizes for rep "SMRep"
+ -- *sorted* by SMRep
+ -- We never have any SpecReps in here, because their
+ -- VarHdrSize is zero
+
+ [SMRep__Int] -- PLUS: for each elem in this list:
+ -- "Int" TotHdrSizes for rep "SMRep"
+ -- *sorted* by SMRep
+ -- We never have any SpecReps in here, because
+ -- their TotHdrSize is just FixedHdrSize
+
+ | MaxHeapOffset HeapOffset HeapOffset
+ | SubHeapOffset HeapOffset HeapOffset
+ | AddHeapOffset HeapOffset HeapOffset
+ | ZeroHeapOffset
+
+ deriving () -- but: see `eqOff` below
+
+#if defined(__GLASGOW_HASKELL__)
+data SMRep__Int = SMRI_ SMRep Int#
+#define SMRI(a,b) (SMRI_ a b)
+#else
+type SMRep__Int = (SMRep, Int)
+#define SMRI(a,b) (a, b)
+#endif
+
+type VirtualHeapOffset = HeapOffset
+type VirtualSpAOffset = Int
+type VirtualSpBOffset = Int
+
+type HpRelOffset = HeapOffset
+type SpARelOffset = Int
+type SpBRelOffset = Int
+\end{code}
+
+Interface fns for HeapOffsets:
+\begin{code}
+zeroOff = ZeroHeapOffset
+
+intOff IBOX(n) = MkHeapOffset n ILIT(0) [] []
+
+fixedHdrSize = MkHeapOffset ILIT(0) ILIT(1) [] []
+
+totHdrSize sm_rep
+ = if isSpecRep sm_rep -- Tot hdr size for a spec rep is just FixedHdrSize
+ then MkHeapOffset ILIT(0) ILIT(1) [] []
+ else MkHeapOffset ILIT(0) ILIT(0) [] [SMRI(sm_rep, ILIT(1))]
+
+varHdrSize sm_rep
+ = if isSpecRep sm_rep
+ then zeroOff
+ else MkHeapOffset ILIT(0) ILIT(0) [SMRI(sm_rep, ILIT(1))] []
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection[Heap-offset-arithmetic]{Heap offset arithmetic}
+%* *
+%************************************************************************
+
+\begin{code}
+-- For maxOff we do our best when we have something simple to deal with
+maxOff ZeroHeapOffset off2 = off2
+maxOff off1 ZeroHeapOffset = off1
+maxOff off1@(MkHeapOffset int_offs1 fixhdr_offs1 varhdr_offs1 tothdr_offs1)
+ off2@(MkHeapOffset int_offs2 fixhdr_offs2 varhdr_offs2 tothdr_offs2)
+ = if (int_offs1 _LE_ int_offs2) &&
+ (real_fixed1 _LE_ real_fixed2) &&
+ (all negative_or_zero difference_of_real_varhdrs)
+ then
+ off2
+ else
+ if (int_offs2 _LE_ int_offs1) &&
+ (real_fixed2 _LE_ real_fixed1) &&
+ (all positive_or_zero difference_of_real_varhdrs)
+ then
+ off1
+ else
+ MaxHeapOffset off1 off2
+ where
+ -- Normalise, by realising that each tot-hdr is really a
+ -- var-hdr plus a fixed-hdr
+ n_tothdr1 = total_of tothdr_offs1
+ real_fixed1 = fixhdr_offs1 _ADD_ n_tothdr1
+ real_varhdr1 = add_HdrSizes varhdr_offs1 tothdr_offs1
+
+ n_tothdr2 = total_of tothdr_offs2
+ real_fixed2 = fixhdr_offs2 _ADD_ n_tothdr2
+ real_varhdr2 = add_HdrSizes varhdr_offs2 tothdr_offs2
+
+ -- Take the difference of the normalised var-hdrs
+ difference_of_real_varhdrs
+ = add_HdrSizes real_varhdr1 (map negate_HdrSize real_varhdr2)
+ where
+ negate_HdrSize :: SMRep__Int -> SMRep__Int
+ negate_HdrSize SMRI(rep,n) = SMRI(rep, (_NEG_ n))
+
+ positive_or_zero SMRI(rep,n) = n _GE_ ILIT(0)
+ negative_or_zero SMRI(rep,n) = n _LE_ ILIT(0)
+
+ total_of [] = ILIT(0)
+ total_of (SMRI(rep,n):offs) = n _ADD_ total_of offs
+
+maxOff other_off1 other_off2 = MaxHeapOffset other_off1 other_off2
+
+------------------------------------------------------------------
+
+subOff off1 ZeroHeapOffset = off1
+subOff off1
+ (MkHeapOffset int_offs2 fxdhdr_offs2 varhdr_offs2 tothdr_offs2)
+ = addOff off1
+ (MkHeapOffset (_NEG_ int_offs2)
+ (_NEG_ fxdhdr_offs2)
+ (map negate_HdrSize varhdr_offs2)
+ (map negate_HdrSize tothdr_offs2))
+ where
+ negate_HdrSize :: SMRep__Int -> SMRep__Int
+ negate_HdrSize SMRI(rep,n) = SMRI(rep,(_NEG_ n))
+
+subOff other_off1 other_off2 = SubHeapOffset other_off1 other_off2
+
+------------------------------------------------------------------
+
+addOff ZeroHeapOffset off2 = off2
+addOff off1 ZeroHeapOffset = off1
+addOff (MkHeapOffset int_offs1 fxdhdr_offs1 varhdr_offs1 tothdr_offs1)
+ (MkHeapOffset int_offs2 fxdhdr_offs2 varhdr_offs2 tothdr_offs2)
+ = MkHeapOffset
+ (int_offs1 _ADD_ int_offs2)
+ (fxdhdr_offs1 _ADD_ fxdhdr_offs2)
+ (add_HdrSizes varhdr_offs1 varhdr_offs2)
+ (add_HdrSizes tothdr_offs1 tothdr_offs2)
+
+addOff other_off1 other_off2 = AddHeapOffset other_off1 other_off2
+
+------------------------------------------------------------------
+-- not exported:
+--
+add_HdrSizes :: [SMRep__Int] -> [SMRep__Int] -> [SMRep__Int]
+
+add_HdrSizes [] offs2 = offs2
+add_HdrSizes offs1 [] = offs1
+add_HdrSizes as@(off1@(SMRI(rep1,n1)) : offs1) bs@(off2@(SMRI(rep2,n2)) : offs2)
+ = if rep1 `ltSMRepHdr` rep2 then
+ off1 : (add_HdrSizes offs1 bs)
+ else
+ if rep2 `ltSMRepHdr` rep1 then
+ off2 : (add_HdrSizes as offs2)
+ else
+ let
+ n1_plus_n2 = n1 _ADD_ n2
+ in
+ -- So they are the same rep
+ if n1_plus_n2 _EQ_ ILIT(0) then
+ add_HdrSizes offs1 offs2
+ else
+ (SMRI(rep1, n1_plus_n2)) : (add_HdrSizes offs1 offs2)
+\end{code}
+
+\begin{code}
+isZeroOff :: HeapOffset -> Bool
+isZeroOff ZeroHeapOffset = True
+isZeroOff (MaxHeapOffset off1 off2) = isZeroOff off1 && isZeroOff off2
+
+isZeroOff (AddHeapOffset off1 off2) = isZeroOff off1 && isZeroOff off2
+ -- This assumes that AddHeapOffset only has positive arguments
+
+isZeroOff (MkHeapOffset int_offs fxdhdr_offs varhdr_offs tothdr_offs)
+ = int_offs _EQ_ ILIT(0) && fxdhdr_offs _EQ_ ILIT(0) &&
+ null varhdr_offs && null tothdr_offs
+
+isZeroOff (SubHeapOffset off1 off2) = panic "Can't say if a SubHeapOffset is zero"
+\end{code}
+
+@possiblyEqualHeapOffset@ tells if two heap offsets might be equal.
+It has to be conservative, but the situation in which it is used
+(@doSimultaneously@) makes it likely to give a good answer.
+
+\begin{code}
+possiblyEqualHeapOffset :: HeapOffset -> HeapOffset -> Bool
+possiblyEqualHeapOffset o1 o2
+ = case (o1 `subOff` o2) of
+
+ SubHeapOffset _ _ -> True -- Very conservative
+
+ diff -> not (isZeroOff diff) -- Won't be any SubHeapOffsets in diff
+ -- NB: this claim depends on the use of
+ -- heap offsets, so this defn might need
+ -- to be elaborated.
+
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[HeapOffs-printing]{Printing heap offsets}
+%* *
+%************************************************************************
+
+IMPORTANT: @pprHeapOffset@ and @pprHeapOffsetPieces@ guarantee to
+print either a single value, or a parenthesised value. No need for
+the caller to parenthesise.
+
+\begin{code}
+pprHeapOffset :: PprStyle -> HeapOffset -> Unpretty
+
+pprHeapOffset sty ZeroHeapOffset = uppChar '0'
+
+pprHeapOffset sty (MaxHeapOffset off1 off2)
+ = uppBesides [uppPStr SLIT("STG_MAX"), uppLparen,
+ pprHeapOffset sty off1, uppComma, pprHeapOffset sty off2,
+ uppRparen]
+pprHeapOffset sty (AddHeapOffset off1 off2)
+ = uppBesides [uppLparen, pprHeapOffset sty off1, uppChar '+',
+ pprHeapOffset sty off2, uppRparen]
+pprHeapOffset sty (SubHeapOffset off1 off2)
+ = uppBesides [uppLparen, pprHeapOffset sty off1, uppChar '-',
+ pprHeapOffset sty off2, uppRparen]
+
+pprHeapOffset sty (MkHeapOffset int_offs fxdhdr_offs varhdr_offs tothdr_offs)
+ = pprHeapOffsetPieces sty int_offs fxdhdr_offs varhdr_offs tothdr_offs
+\end{code}
+
+\begin{code}
+pprHeapOffsetPieces :: PprStyle
+ -> FAST_INT -- Words
+ -> FAST_INT -- Fixed hdrs
+ -> [SMRep__Int] -- Var hdrs
+ -> [SMRep__Int] -- Tot hdrs
+ -> Unpretty
+
+pprHeapOffsetPieces sty n ILIT(0) [] [] = uppInt IBOX(n) -- Deals with zero case too
+
+pprHeapOffsetPieces sty int_offs fxdhdr_offs varhdr_offs tothdr_offs
+ = let pp_int_offs =
+ if int_offs _EQ_ ILIT(0)
+ then Nothing
+ else Just (uppInt IBOX(int_offs))
+
+ pp_fxdhdr_offs =
+ if fxdhdr_offs _EQ_ ILIT(0) then
+ Nothing
+ else if fxdhdr_offs _EQ_ ILIT(1) then
+ Just (uppPStr SLIT("_FHS"))
+ else
+ Just (uppBesides [uppStr "(_FHS*", uppInt IBOX(fxdhdr_offs), uppChar ')'])
+
+ pp_varhdr_offs = pp_hdrs (uppPStr SLIT("_VHS")) varhdr_offs
+
+ pp_tothdr_offs = pp_hdrs (uppPStr SLIT("_HS")) tothdr_offs
+ in
+ case (catMaybes [pp_tothdr_offs, pp_varhdr_offs, pp_fxdhdr_offs, pp_int_offs]) of
+ [] -> uppChar '0'
+ [pp] -> pp -- Each blob is parenthesised if necessary
+ pps -> uppBesides [ uppLparen, uppIntersperse (uppChar '+') pps, uppRparen ]
+ where
+ pp_hdrs hdr_pp [] = Nothing
+ pp_hdrs hdr_pp [SMRI(rep, n)] | n _EQ_ ILIT(1) = Just (uppBeside (uppStr (show rep)) hdr_pp)
+ pp_hdrs hdr_pp hdrs = Just (uppBesides [ uppLparen,
+ uppInterleave (uppChar '+')
+ (map (pp_hdr hdr_pp) hdrs),
+ uppRparen ])
+
+ pp_hdr :: Unpretty -> SMRep__Int -> Unpretty
+ pp_hdr pp_str (SMRI(rep, n))
+ = if n _EQ_ ILIT(1) then
+ uppBeside (uppStr (show rep)) pp_str
+ else
+ uppBesides [uppInt IBOX(n), uppChar '*', uppStr (show rep), pp_str]
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[HeapOffs-conversion]{Converting heap offsets to words}
+%* *
+%************************************************************************
+
+@intOffsetIntoGoods@ and @hpRelToInt@ convert HeapOffsets into Ints.
+
+@intOffsetIntoGoods@ {\em tries} to convert a HeapOffset in a SPEC
+closure into an Int, returning the (0-origin) index from the beginning
+of the ``goods'' in the closure. [SPECs don't have VHSs, by
+definition, so the index is merely ignoring the FHS].
+
+@hpRelToInt@ is for the native code-generator(s); it is courtesy of
+Jon Hill and the DAP code generator. We've just abstracted away some
+of the implementation-dependent bits.
+
+\begin{code}
+intOffsetIntoGoods :: HeapOffset -> Maybe Int
+
+intOffsetIntoGoods (MkHeapOffset n ILIT(1){-FHS-} [{-no VHSs-}] [{-no totHSs-}])
+ = Just IBOX(n)
+intOffsetIntoGoods anything_else = Nothing
+\end{code}
+
+\begin{code}
+#if ! OMIT_NATIVE_CODEGEN
+
+hpRelToInt :: Target -> HeapOffset -> Int
+
+hpRelToInt target (MaxHeapOffset left right)
+ = (hpRelToInt target left) `max` (hpRelToInt target right)
+
+hpRelToInt target (SubHeapOffset left right)
+ = (hpRelToInt target left) - (hpRelToInt target right)
+
+hpRelToInt target (AddHeapOffset left right)
+ = (hpRelToInt target left) + (hpRelToInt target right)
+
+hpRelToInt target ZeroHeapOffset = 0
+
+hpRelToInt target (MkHeapOffset base fhs vhs ths)
+ = let
+ vhs_pieces, ths_pieces :: [Int]
+ fhs_off, vhs_off, ths_off :: Int
+
+ vhs_pieces = map (\ (SMRI(r, n)) -> vhs_size r * IBOX(n)) vhs
+ ths_pieces = map (\ (SMRI(r, n)) -> (fhs_size + vhs_size r) * IBOX(n)) ths
+
+ fhs_off = fhs_size * IBOX(fhs)
+ vhs_off = sum vhs_pieces
+ ths_off = sum ths_pieces
+ in
+ IBOX(base) + fhs_off + vhs_off + ths_off
+ where
+ fhs_size = (fixedHeaderSize target) :: Int
+ vhs_size r = (varHeaderSize target r) :: Int
+
+#endif
+\end{code}