2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 % $Id: CgStackery.lhs,v 1.19 2001/09/12 15:52:40 sewardj Exp $
6 \section[CgStackery]{Stack management functions}
8 Stack-twiddling operations, which are pretty low-down and grimy.
9 (This is the module that knows all about stack layouts, etc.)
13 allocStack, allocPrimStack, allocStackTop, deAllocStackTop,
14 adjustStackHW, getFinalStackHW,
15 mkTaggedVirtStkOffsets, mkTaggedStkAmodes, mkTagAssts,
16 freeStackSlots, dataStackSlots, addFreeSlots,
17 updateFrameSize, seqFrameSize
20 #include "HsVersions.h"
25 import CgUsages ( getRealSp )
26 import AbsCUtils ( mkAbstractCs, getAmodeRep )
27 import PrimRep ( getPrimRepSize, PrimRep(..), isFollowableRep )
28 import CmdLineOpts ( opt_SccProfilingOn, opt_GranMacros )
29 import Panic ( panic )
30 import Constants ( uF_SIZE, sCC_UF_SIZE, gRAN_UF_SIZE,
31 sEQ_FRAME_SIZE, sCC_SEQ_FRAME_SIZE, gRAN_SEQ_FRAME_SIZE )
33 import Util ( sortLt )
34 import IOExts ( trace )
37 %************************************************************************
39 \subsection[CgStackery-layout]{Laying out a stack frame}
41 %************************************************************************
43 @mkTaggedVirtStkOffsets@ is given a list of arguments. The first
44 argument gets the {\em largest} virtual stack offset (remember,
45 virtual offsets increase towards the top of stack). This function
46 also computes the correct tagging arrangement for standard function
47 entry points. Each non-pointer on the stack is preceded by a tag word
48 indicating the number of non-pointer words above it on the stack.
50 offset --> | | <---- last allocated stack word
54 | | total_nptrs (words)
58 offset + tot_nptrs + 1 --> | tag |
62 mkTaggedVirtStkOffsets
63 :: VirtualSpOffset -- Offset of the last allocated thing
64 -> (a -> PrimRep) -- to be able to grab kinds
65 -> [a] -- things to make offsets for
66 -> (VirtualSpOffset, -- OUTPUTS: Topmost allocated word
67 [(a, VirtualSpOffset)], -- things with offsets
68 [(VirtualSpOffset,Int)]) -- offsets for tags
70 mkTaggedVirtStkOffsets init_Sp_offset kind_fun things
71 = loop init_Sp_offset [] [] (reverse things)
73 loop offset tags offs [] = (offset,offs,tags)
74 loop offset tags offs (t:things)
75 | isFollowableRep (kind_fun t) =
76 loop (offset+1) tags ((t,offset+1):offs) things
79 size = getPrimRepSize (kind_fun t)
80 tag_slot = offset+size+1
82 loop tag_slot ((tag_slot,size):tags) ((t,offset+size):offs) things
83 -- offset of thing is offset+size, because we're growing the stack
84 -- *downwards* as the offsets increase.
87 @mkTaggedStkAmodes@ is a higher-level version of
88 @mkTaggedVirtStkOffsets@. It starts from the tail-call locations. It
89 returns a single list of addressing modes for the stack locations, and
90 therefore is in the monad.
92 It *doesn't* adjust the high water mark.
96 :: VirtualSpOffset -- Tail call positions
97 -> [CAddrMode] -- things to make offsets for
98 -> FCode (VirtualSpOffset, -- OUTPUTS: Topmost allocated word
99 AbstractC, -- Assignments to appropriate stk slots
100 AbstractC) -- Assignments for tagging
102 mkTaggedStkAmodes tail_Sp things
103 = getRealSp `thenFC` \ realSp ->
105 (last_Sp_offset, offsets, tags)
106 = mkTaggedVirtStkOffsets tail_Sp getAmodeRep things
109 [ CAssign (CVal (spRel realSp offset) (getAmodeRep thing)) thing
110 | (thing, offset) <- offsets
114 [ CAssign (CVal (spRel realSp offset) WordRep)
115 (CMacroExpr WordRep ARG_TAG [mkIntCLit size])
116 | (offset,size) <- tags
119 returnFC (last_Sp_offset, mkAbstractCs abs_cs, mkAbstractCs tag_cs)
121 mkTagAssts :: [(VirtualSpOffset,Int)] -> FCode AbstractC
123 getRealSp `thenFC` \realSp ->
124 returnFC (mkAbstractCs
125 [ CAssign (CVal (spRel realSp offset) WordRep)
126 (CMacroExpr WordRep ARG_TAG [mkIntCLit size])
127 | (offset,size) <- tags
132 %************************************************************************
134 \subsection[CgStackery-monadery]{Inside-monad functions for stack manipulation}
136 %************************************************************************
138 Allocate a virtual offset for something.
141 allocStack :: FCode VirtualSpOffset
142 allocStack = allocPrimStack 1
144 allocPrimStack :: Int -> FCode VirtualSpOffset
145 allocPrimStack size = do
146 ((virt_sp, free_stk, real_sp, hw_sp),h_usage) <- getUsage
147 let push_virt_sp = virt_sp + size
148 let (chosen_slot, new_stk_usage) =
149 case find_block free_stk of
150 Nothing -> (push_virt_sp, (push_virt_sp, free_stk, real_sp,
151 hw_sp `max` push_virt_sp))
152 -- Adjust high water mark
153 Just slot -> (slot, (virt_sp,
154 delete_block free_stk slot, real_sp, hw_sp))
155 setUsage (new_stk_usage, h_usage)
159 -- find_block looks for a contiguous chunk of free slots
160 find_block :: [(VirtualSpOffset,Slot)] -> Maybe VirtualSpOffset
161 find_block [] = Nothing
162 find_block ((off,free):slots)
163 | take size ((off,free):slots) ==
164 zip [off..top_slot] (repeat Free) = Just top_slot
165 | otherwise = find_block slots
166 -- The stack grows downwards, with increasing virtual offsets.
167 -- Therefore, the address of a multi-word object is the *highest*
168 -- virtual offset it occupies (top_slot below).
169 where top_slot = off+size-1
171 delete_block free_stk slot = [ (s,f) | (s,f) <- free_stk,
172 (s<=slot-size) || (s>slot) ]
173 -- Retain slots which are not in the range
177 Allocate a chunk ON TOP OF the stack.
179 ToDo: should really register this memory as NonPointer stuff in the
183 allocStackTop :: Int -> FCode VirtualSpOffset
184 allocStackTop size = do
185 ((virt_sp, free_stk, real_sp, hw_sp), h_usage) <- getUsage
186 let push_virt_sp = virt_sp + size
187 let new_stk_usage = (push_virt_sp, free_stk, real_sp, hw_sp `max` push_virt_sp)
188 setUsage (new_stk_usage, h_usage)
192 Pop some words from the current top of stack. This is used for
193 de-allocating the return address in a case alternative.
196 deAllocStackTop :: Int -> FCode VirtualSpOffset
197 deAllocStackTop size = do
198 ((virt_sp, free_stk, real_sp, hw_sp), h_usage) <- getUsage
199 let pop_virt_sp = virt_sp - size
200 let new_stk_usage = (pop_virt_sp, free_stk, real_sp, hw_sp)
201 setUsage (new_stk_usage, h_usage)
206 adjustStackHW :: VirtualSpOffset -> Code
207 adjustStackHW offset = do
208 ((vSp,fSp,realSp,hwSp), h_usage) <- getUsage
209 setUsage ((vSp, fSp, realSp, max offset hwSp), h_usage)
215 getFinalStackHW :: (VirtualSpOffset -> Code) -> Code
216 getFinalStackHW fcode = do
219 ((_,_,_, hwSp),_) <- getUsage
225 updateFrameSize | opt_SccProfilingOn = sCC_UF_SIZE
226 | opt_GranMacros = trace ("updateFrameSize = " ++ (show gRAN_UF_SIZE))gRAN_UF_SIZE
227 | otherwise = uF_SIZE
229 seqFrameSize | opt_SccProfilingOn = sCC_SEQ_FRAME_SIZE
230 | opt_GranMacros = gRAN_SEQ_FRAME_SIZE
231 | otherwise = sEQ_FRAME_SIZE
234 %************************************************************************
236 \subsection[CgStackery-free]{Free stack slots}
238 %************************************************************************
240 Explicitly free some stack space.
243 addFreeStackSlots :: [VirtualSpOffset] -> Slot -> Code
244 addFreeStackSlots extra_free slot = do
245 ((vsp, free, real, hw),heap_usage) <- getUsage
246 let all_free = addFreeSlots free (zip (sortLt (<) extra_free) (repeat slot))
247 let (new_vsp, new_free) = trim vsp all_free
248 let new_usage = ((new_vsp, new_free, real, hw), heap_usage)
251 freeStackSlots :: [VirtualSpOffset] -> Code
252 freeStackSlots slots = addFreeStackSlots slots Free
254 dataStackSlots :: [VirtualSpOffset] -> Code
255 dataStackSlots slots = addFreeStackSlots slots NonPointer
257 addFreeSlots :: [(Int,Slot)] -> [(Int,Slot)] -> [(Int,Slot)]
258 addFreeSlots cs [] = cs
259 addFreeSlots [] ns = ns
260 addFreeSlots ((c,s):cs) ((n,s'):ns)
262 (c,s) : addFreeSlots cs ((n,s'):ns)
264 (n,s') : addFreeSlots ((c,s):cs) ns
265 else if s /= s' then -- c == n
266 (c,s') : addFreeSlots cs ns
268 panic ("addFreeSlots: equal slots: " ++ show (c:map fst cs)
269 ++ show (n:map fst ns))
271 trim :: Int{-offset-} -> [(Int,Slot)] -> (Int{-offset-}, [(Int,Slot)])
272 trim current_sp free_slots
273 = try current_sp free_slots
275 try csp [] = (csp,[])
277 try csp (slot@(off,state):slots) =
278 if state == Free && null slots' then
281 else if csp' == off then
288 (csp',slots') = try csp slots