[project @ 1999-06-24 13:04:13 by simonmar]
[ghc-hetmet.git] / ghc / compiler / codeGen / CgStackery.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3 %
4 % $Id: CgStackery.lhs,v 1.12 1999/06/24 13:04:20 simonmar Exp $
5 %
6 \section[CgStackery]{Stack management functions}
7
8 Stack-twiddling operations, which are pretty low-down and grimy.
9 (This is the module that knows all about stack layouts, etc.)
10
11 \begin{code}
12 module CgStackery (
13         allocStack, allocPrimStack, allocStackTop, deAllocStackTop,
14         adjustStackHW, getFinalStackHW,
15         mkTaggedVirtStkOffsets, mkTaggedStkAmodes, mkTagAssts,
16         freeStackSlots, dataStackSlots, addFreeSlots,
17         updateFrameSize, seqFrameSize
18     ) where
19
20 #include "HsVersions.h"
21
22 import CgMonad
23 import AbsCSyn
24
25 import CgUsages         ( getRealSp )
26 import AbsCUtils        ( mkAbstractCs, mkAbsCStmts, getAmodeRep )
27 import PrimRep          ( getPrimRepSize, PrimRep(..), isFollowableRep )
28 import CmdLineOpts      ( opt_SccProfilingOn )
29 import Panic            ( panic )
30 import Constants        ( uF_SIZE, sCC_UF_SIZE, sEQ_FRAME_SIZE, sCC_SEQ_FRAME_SIZE )
31
32 import IOExts           ( trace )
33 \end{code}
34
35 %************************************************************************
36 %*                                                                      *
37 \subsection[CgStackery-layout]{Laying out a stack frame}
38 %*                                                                      *
39 %************************************************************************
40
41 @mkTaggedVirtStkOffsets@ is given a list of arguments.  The first
42 argument gets the {\em largest} virtual stack offset (remember,
43 virtual offsets increase towards the top of stack).  This function
44 also computes the correct tagging arrangement for standard function
45 entry points.  Each non-pointer on the stack is preceded by a tag word
46 indicating the number of non-pointer words above it on the stack.
47
48                 offset --> |       |  <---- last allocated stack word
49                            ---------  <
50                            |       |  .
51                            ---------  .
52                            |       |  total_nptrs (words)
53                            ---------  .
54                            |       |  .
55                            ---------  <
56 offset + tot_nptrs + 1 --> |  tag  |  
57                            ---------
58
59 \begin{code}
60 mkTaggedVirtStkOffsets
61           :: VirtualSpOffset    -- Offset of the last allocated thing
62           -> (a -> PrimRep)     -- to be able to grab kinds
63           -> [a]                        -- things to make offsets for
64           -> (VirtualSpOffset,          -- OUTPUTS: Topmost allocated word
65               [(a, VirtualSpOffset)],   -- things with offsets
66               [(VirtualSpOffset,Int)])  -- offsets for tags
67
68 mkTaggedVirtStkOffsets init_Sp_offset kind_fun things
69     = loop init_Sp_offset [] [] (reverse things)
70   where
71     loop offset tags offs [] = (offset,offs,tags)
72     loop offset tags offs (t:things) 
73          | isFollowableRep (kind_fun t) =
74              loop (offset+1) tags ((t,offset+1):offs) things
75          | otherwise =
76              let
77                  size = getPrimRepSize (kind_fun t)
78                  tag_slot = offset+size+1
79              in
80              loop tag_slot ((tag_slot,size):tags) ((t,offset+size):offs) things
81     -- offset of thing is offset+size, because we're growing the stack
82     -- *downwards* as the offsets increase.
83 \end{code}
84
85 @mkTaggedStkAmodes@ is a higher-level version of
86 @mkTaggedVirtStkOffsets@.  It starts from the tail-call locations.  It
87 returns a single list of addressing modes for the stack locations, and
88 therefore is in the monad.
89
90 It *doesn't* adjust the high water mark.  
91
92 \begin{code}
93 mkTaggedStkAmodes 
94         :: VirtualSpOffset          -- Tail call positions
95         -> [CAddrMode]              -- things to make offsets for
96         -> FCode (VirtualSpOffset,  -- OUTPUTS: Topmost allocated word
97                   AbstractC,        -- Assignments to appropriate stk slots
98                   AbstractC)        -- Assignments for tagging
99
100 mkTaggedStkAmodes tail_Sp things
101   = getRealSp `thenFC` \ realSp ->
102     let
103       (last_Sp_offset, offsets, tags)
104         = mkTaggedVirtStkOffsets tail_Sp getAmodeRep things
105
106       abs_cs =
107           [ CAssign (CVal (spRel realSp offset) (getAmodeRep thing)) thing
108           | (thing, offset) <- offsets
109           ]
110  
111       tag_cs =
112           [ CAssign (CVal (spRel realSp offset) WordRep)
113                     (CMacroExpr WordRep ARG_TAG [mkIntCLit size])
114           | (offset,size) <- tags
115           ]
116     in
117     returnFC (last_Sp_offset, mkAbstractCs abs_cs, mkAbstractCs tag_cs)
118
119 mkTagAssts :: [(VirtualSpOffset,Int)] -> FCode AbstractC
120 mkTagAssts tags = 
121    getRealSp `thenFC` \realSp ->
122    returnFC (mkAbstractCs
123           [ CAssign (CVal (spRel realSp offset) WordRep)
124                     (CMacroExpr WordRep ARG_TAG [mkIntCLit size])
125           | (offset,size) <- tags
126           ])
127
128 \end{code}
129
130 %************************************************************************
131 %*                                                                      *
132 \subsection[CgStackery-monadery]{Inside-monad functions for stack manipulation}
133 %*                                                                      *
134 %************************************************************************
135
136 Allocate a virtual offset for something.
137
138 \begin{code}
139 allocStack :: FCode VirtualSpOffset
140 allocStack = allocPrimStack 1
141
142 allocPrimStack :: Int -> FCode VirtualSpOffset
143 allocPrimStack size info_down (MkCgState absC binds
144                                  ((virt_sp, free_stk, real_sp, hw_sp), h_usage))
145   = (chosen_slot, MkCgState absC binds (new_stk_usage, h_usage))
146   where
147     push_virt_sp = virt_sp + size
148
149     (chosen_slot, new_stk_usage)
150         = case find_block free_stk of
151                 Nothing -> (push_virt_sp, (push_virt_sp, free_stk, real_sp,
152                                        hw_sp `max` push_virt_sp))
153                                        -- Adjust high water mark
154
155                 Just slot -> (slot, (virt_sp, 
156                                     delete_block free_stk slot, real_sp, hw_sp))
157
158     -- find_block looks for a contiguous chunk of free slots
159     find_block :: [(VirtualSpOffset,Slot)] -> Maybe VirtualSpOffset
160     find_block [] = Nothing
161     find_block ((off,free):slots)
162       | take size ((off,free):slots) == 
163                 zip [off..top_slot] (repeat Free) = Just top_slot
164       | otherwise                                  = find_block slots
165         -- The stack grows downwards, with increasing virtual offsets.
166         -- Therefore, the address of a multi-word object is the *highest*
167         -- virtual offset it occupies (top_slot below).
168       where top_slot = off+size-1
169
170     delete_block free_stk slot = [ (s,f) | (s,f) <- free_stk, 
171                                            (s<=slot-size) || (s>slot) ]
172                               -- Retain slots which are not in the range
173                               -- slot-size+1..slot
174 \end{code}
175
176 Allocate a chunk ON TOP OF the stack.  
177
178 ToDo: should really register this memory as NonPointer stuff in the
179 free list.
180
181 \begin{code}
182 allocStackTop :: Int -> FCode VirtualSpOffset
183 allocStackTop size info_down (MkCgState absC binds
184                              ((virt_sp, free_stk, real_sp, hw_sp), h_usage))
185   = (push_virt_sp, MkCgState absC binds (new_stk_usage, h_usage))
186   where
187     push_virt_sp = virt_sp + size
188     new_stk_usage = (push_virt_sp, free_stk, real_sp, hw_sp `max` push_virt_sp)
189                                                 -- Adjust high water mark
190 \end{code}
191
192 Pop some words from the current top of stack.  This is used for
193 de-allocating the return address in a case alternative.
194
195 \begin{code}
196 deAllocStackTop :: Int -> FCode VirtualSpOffset
197 deAllocStackTop size info_down (MkCgState absC binds
198                              ((virt_sp, free_stk, real_sp, hw_sp), h_usage))
199   = (pop_virt_sp, MkCgState absC binds (new_stk_usage, h_usage))
200   where
201     pop_virt_sp = virt_sp - size
202     new_stk_usage = (pop_virt_sp, free_stk, real_sp, hw_sp)
203 \end{code}
204
205 \begin{code}
206 adjustStackHW :: VirtualSpOffset -> Code
207 adjustStackHW offset info_down (MkCgState absC binds usage) 
208   = MkCgState absC binds new_usage
209   where
210     ((vSp,fSp,realSp,hwSp), h_usage) = usage
211     new_usage = ((vSp, fSp, realSp, max offset hwSp), h_usage)
212     -- No need to fiddle with virtual Sp etc because this call is
213     -- only done just before the end of a block
214 \end{code}
215
216 A knot-tying beast.
217
218 \begin{code}
219 getFinalStackHW :: (VirtualSpOffset -> Code) -> Code
220 getFinalStackHW fcode info_down (MkCgState absC binds usages) = state1
221   where
222     state1 = fcode hwSp info_down (MkCgState absC binds usages)
223     (MkCgState _ _ ((_,_,_, hwSp), _)) = state1
224 \end{code}
225
226 \begin{code}
227 updateFrameSize | opt_SccProfilingOn = sCC_UF_SIZE
228                 | otherwise          = uF_SIZE
229
230 seqFrameSize    | opt_SccProfilingOn  = sCC_SEQ_FRAME_SIZE
231                 | otherwise           = sEQ_FRAME_SIZE
232 \end{code}                      
233
234 %************************************************************************
235 %*                                                                      *
236 \subsection[CgStackery-free]{Free stack slots}
237 %*                                                                      *
238 %************************************************************************
239
240 Explicitly free some stack space.
241
242 \begin{code}
243 addFreeStackSlots :: [VirtualSpOffset] -> Slot -> Code
244 addFreeStackSlots extra_free slot info_down
245         state@(MkCgState abs_c binds ((vsp, free, real, hw), heap_usage))
246   = MkCgState abs_c binds new_usage
247   where
248     new_usage = ((new_vsp, new_free, real, hw), heap_usage)
249     (new_vsp, new_free) = trim vsp all_free
250     all_free = addFreeSlots free (zip extra_free (repeat slot))
251
252 freeStackSlots :: [VirtualSpOffset] -> Code
253 freeStackSlots slots = addFreeStackSlots slots Free
254
255 dataStackSlots :: [VirtualSpOffset] -> Code
256 dataStackSlots slots = addFreeStackSlots slots NonPointer
257
258 addFreeSlots :: [(Int,Slot)] -> [(Int,Slot)] -> [(Int,Slot)]
259 addFreeSlots cs [] = cs
260 addFreeSlots [] ns = ns
261 addFreeSlots ((c,s):cs) ((n,s'):ns)
262  = if c < n then
263         (c,s) : addFreeSlots cs ((n,s'):ns)
264    else if c > n then
265         (n,s') : addFreeSlots ((c,s):cs) ns
266    else if s /= s' then -- c == n
267         (c,s') : addFreeSlots cs ns
268    else
269         panic ("addFreeSlots: equal slots: " ++ show (c:map fst cs)
270                                              ++ show (n:map fst ns))
271
272 trim :: Int{-offset-} -> [(Int,Slot)] -> (Int{-offset-}, [(Int,Slot)])
273 trim current_sp free_slots
274   = try current_sp free_slots
275   where
276         try csp [] = (csp,[])
277
278         try csp (slot@(off,state):slots) = 
279                 if state == Free && null slots' then
280                     if csp' < off then 
281                         (csp', [])
282                     else if csp' == off then
283                         (csp'-1, [])
284                     else 
285                         (csp',[slot])
286                 else
287                     (csp', slot:slots')
288                 where
289                     (csp',slots') = try csp slots
290 \end{code}