2 % (c) The AQUA Project, Glasgow University, 1993-1998
6 module StixMacro ( macroCode, checkCode ) where
8 #include "HsVersions.h"
9 #include "nativeGen/NCG.h"
11 import {-# SOURCE #-} StixPrim ( amodeToStix )
15 import AbsCSyn ( CStmtMacro(..), MagicId(..), CAddrMode, tagreg,
17 import Constants ( uF_RET, uF_SU, uF_UPDATEE, uF_SIZE, sEQ_FRAME_SIZE )
18 import CallConv ( cCallConv )
19 import PrimOp ( PrimOp(..) )
20 import PrimRep ( PrimRep(..) )
22 import UniqSupply ( returnUs, thenUs, UniqSM )
24 import CLabel ( mkBlackHoleInfoTableLabel, mkIndStaticInfoLabel,
25 mkIndInfoLabel, mkUpdInfoLabel, mkSeqInfoLabel,
26 mkRtsGCEntryLabel, mkStgUpdatePAPLabel )
29 The @ARGS_CHK_A{_LOAD_NODE}@ macros check for sufficient arguments on
30 the A stack, and perform a tail call to @UpdatePAP@ if the arguments are
31 not there. The @_LOAD_NODE@ version also loads R1 with an appropriate
36 :: CStmtMacro -- statement macro
37 -> [CAddrMode] -- args
38 -> UniqSM StixTreeList
41 -----------------------------------------------------------------------------
42 Argument satisfaction checks.
45 macroCode ARGS_CHK_LOAD_NODE args
46 = getUniqLabelNCG `thenUs` \ ulbl ->
48 [words, lbl] = map amodeToStix args
49 temp = StIndex PtrRep stgSp words
50 test = StPrim AddrGeOp [stgSu, temp]
51 cjmp = StCondJump ulbl test
52 assign = StAssign PtrRep stgNode lbl
55 returnUs (\xs -> cjmp : assign : updatePAP : join : xs)
57 macroCode ARGS_CHK [words]
58 = getUniqLabelNCG `thenUs` \ ulbl ->
59 let temp = StIndex PtrRep stgSp (amodeToStix words)
60 test = StPrim AddrGeOp [stgSu, temp]
61 cjmp = StCondJump ulbl test
64 returnUs (\xs -> cjmp : updatePAP : join : xs)
67 -----------------------------------------------------------------------------
70 @UPD_CAF@ involves changing the info pointer of the closure, and
71 adding an indirection.
74 macroCode UPD_CAF args
76 [cafptr,bhptr] = map amodeToStix args
77 w0 = StInd PtrRep cafptr
78 w1 = StInd PtrRep (StIndex PtrRep cafptr fixedHS)
79 blocking_queue = StInd PtrRep (StIndex PtrRep bhptr fixedHS)
80 a1 = StAssign PtrRep w0 ind_static_info
81 a2 = StAssign PtrRep w1 bhptr
82 a3 = StCall SLIT("newCAF") cCallConv VoidRep [cafptr]
84 returnUs (\xs -> a1 : a2 : a3 : xs)
87 -----------------------------------------------------------------------------
90 We do lazy blackholing: no need to overwrite thunks with blackholes
91 the minute they're entered, as long as we do it before a context
92 switch or garbage collection, that's ok.
94 Don't blackhole single entry closures, for the following reasons:
96 - if the compiler has decided that they won't be entered again,
97 that probably means that nothing has a pointer to it
98 (not necessarily true, but...)
100 - no need to blackhole for concurrency reasons, because nothing
101 can block on the result of this computation.
104 macroCode UPD_BH_UPDATABLE args = returnUs id
106 macroCode UPD_BH_SINGLE_ENTRY args = returnUs id
109 update = StAssign PtrRep (StInd PtrRep (amodeToStix arg)) bh_info
111 returnUs (\xs -> update : xs)
115 -----------------------------------------------------------------------------
118 Push a four word update frame on the stack and slide the Su registers
119 to the current Sp location.
122 macroCode PUSH_UPD_FRAME args
124 [bhptr, _{-0-}] = map amodeToStix args
125 frame n = StInd PtrRep
126 (StIndex PtrRep stgSp (StInt (toInteger (n-uF_SIZE))))
128 -- HWL: these values are *wrong* in a GranSim setup; ToDo: fix
129 a1 = StAssign PtrRep (frame uF_RET) upd_frame_info
130 a3 = StAssign PtrRep (frame uF_SU) stgSu
131 a4 = StAssign PtrRep (frame uF_UPDATEE) bhptr
133 updSu = StAssign PtrRep stgSu
134 (StIndex PtrRep stgSp (StInt (toInteger (-uF_SIZE))))
136 returnUs (\xs -> a1 : a3 : a4 : updSu : xs)
139 macroCode PUSH_SEQ_FRAME args
140 = let [arg_frame] = map amodeToStix args
141 frame n = StInd PtrRep
142 (StIndex PtrRep arg_frame (StInt (toInteger n)))
143 a1 = StAssign PtrRep (frame 0) seq_frame_info
144 a2 = StAssign PtrRep (frame 1) stgSu
145 updSu = StAssign PtrRep stgSu arg_frame
147 returnUs (\xs -> a1 : a2 : updSu : xs)
150 macroCode UPDATE_SU_FROM_UPD_FRAME args
151 = let [arg_frame] = map amodeToStix args
152 frame n = StInd PtrRep
153 (StIndex PtrRep arg_frame (StInt (toInteger n)))
155 = StAssign PtrRep stgSu (frame uF_SU)
157 returnUs (\xs -> updSu : xs)
160 -----------------------------------------------------------------------------
161 Setting the tag register
163 This one only applies if we have a machine register devoted to TagReg.
166 macroCode SET_TAG [tag]
167 = let set_tag = StAssign IntRep stgTagReg (amodeToStix tag)
169 case stgReg tagreg of
170 Always _ -> returnUs id
171 Save _ -> returnUs (\ xs -> set_tag : xs)
174 -----------------------------------------------------------------------------
177 macroCode REGISTER_IMPORT [arg]
179 \xs -> StAssign WordRep (StInd WordRep stgSp) (amodeToStix arg)
180 : StAssign PtrRep stgSp (StPrim IntAddOp [stgSp, StInt 4])
184 macroCode REGISTER_FOREIGN_EXPORT [arg]
186 \xs -> StCall SLIT("getStablePtr") cCallConv VoidRep [amodeToStix arg]
192 SET_TAG -> error "foobarxyzzy8"
193 _ -> error "StixMacro.macroCode: unknown macro/args"
197 Do the business for a @HEAP_CHK@, having converted the args to Trees
200 -----------------------------------------------------------------------------
201 Let's make sure that these CAFs are lifted out, shall we?
204 -- Some common labels
206 bh_info, ind_static_info, ind_info :: StixTree
208 bh_info = StCLbl mkBlackHoleInfoTableLabel
209 ind_static_info = StCLbl mkIndStaticInfoLabel
210 ind_info = StCLbl mkIndInfoLabel
211 upd_frame_info = StCLbl mkUpdInfoLabel
212 seq_frame_info = StCLbl mkSeqInfoLabel
213 stg_update_PAP = StCLbl mkStgUpdatePAPLabel
214 -- Some common call trees
216 updatePAP, stackOverflow :: StixTree
218 updatePAP = StJump stg_update_PAP
219 stackOverflow = StCall SLIT("StackOverflow") cCallConv VoidRep []
222 -----------------------------------------------------------------------------
226 checkCode :: CCheckMacro -> [CAddrMode] -> StixTreeList -> UniqSM StixTreeList
227 checkCode macro args assts
228 = getUniqLabelNCG `thenUs` \ ulbl_fail ->
229 getUniqLabelNCG `thenUs` \ ulbl_pass ->
231 let args_stix = map amodeToStix args
232 newHp wds = StIndex PtrRep stgHp wds
233 assign_hp wds = StAssign PtrRep stgHp (newHp wds)
234 test_hp = StPrim AddrLeOp [stgHp, stgHpLim]
235 cjmp_hp = StCondJump ulbl_pass test_hp
237 newSp wds = StIndex PtrRep stgSp (StPrim IntNegOp [wds])
238 test_sp_pass wds = StPrim AddrGeOp [newSp wds, stgSpLim]
239 test_sp_fail wds = StPrim AddrLtOp [newSp wds, stgSpLim]
240 cjmp_sp_pass wds = StCondJump ulbl_pass (test_sp_pass wds)
241 cjmp_sp_fail wds = StCondJump ulbl_fail (test_sp_fail wds)
243 assign_ret r ret = StAssign CodePtrRep r ret
245 fail = StLabel ulbl_fail
246 join = StLabel ulbl_pass
248 -- see includes/StgMacros.h for explaination of these magic consts
250 = IF_ARCH_alpha(16383,65535)
252 assign_liveness ptr_regs
253 = StAssign WordRep stgR9
254 (StPrim XorOp [StInt aLL_NON_PTRS, ptr_regs])
255 assign_reentry reentry
256 = StAssign WordRep stgR10 reentry
262 let [words,ptrs] = args_stix
263 in (\xs -> assign_hp words : cjmp_hp :
264 assts (gc_enter ptrs : join : xs))
267 let [words,ptrs] = args_stix
268 in (\xs -> assign_hp words : cjmp_hp :
269 assts (gc_seq ptrs : join : xs))
272 let [words,ptrs] = args_stix
273 in (\xs -> cjmp_sp_pass words :
274 assts (gc_enter ptrs : join : xs))
277 let [sp_words,hp_words,ptrs] = args_stix
278 in (\xs -> cjmp_sp_fail sp_words :
279 assign_hp hp_words : cjmp_hp :
281 assts (gc_enter ptrs : join : xs))
284 let [words,ret,r,ptrs] = args_stix
285 in (\xs -> assign_hp words : cjmp_hp :
286 assts (assign_ret r ret : gc_chk ptrs : join : xs))
289 let [words,ret,r,ptrs] = args_stix
290 in (\xs -> cjmp_sp_pass words :
291 assts (assign_ret r ret : gc_chk ptrs : join : xs))
294 let [sp_words,hp_words,ret,r,ptrs] = args_stix
295 in (\xs -> cjmp_sp_fail sp_words :
296 assign_hp hp_words : cjmp_hp :
298 assts (assign_ret r ret : gc_chk ptrs : join : xs))
301 let [words] = args_stix
302 in (\xs -> assign_hp words : cjmp_hp :
303 assts (gc_noregs : join : xs))
306 let [words] = args_stix
307 in (\xs -> assign_hp words : cjmp_hp :
308 assts (gc_unpt_r1 : join : xs))
311 let [words] = args_stix
312 in (\xs -> assign_hp words : cjmp_hp :
313 assts (gc_unbx_r1 : join : xs))
316 let [words] = args_stix
317 in (\xs -> assign_hp words : cjmp_hp :
318 assts (gc_f1 : join : xs))
321 let [words] = args_stix
322 in (\xs -> assign_hp words : cjmp_hp :
323 assts (gc_d1 : join : xs))
326 let [words,ptrs,nonptrs,r,ret] = args_stix
327 in (\xs -> assign_hp words : cjmp_hp :
328 assts (assign_ret r ret : gc_ut ptrs nonptrs
332 let [words,liveness,reentry] = args_stix
333 in (\xs -> assign_hp words : cjmp_hp :
334 assts (assign_liveness liveness :
335 assign_reentry reentry :
339 -- Various canned heap-check routines
341 mkStJump_to_GCentry :: String -> StixTree
342 mkStJump_to_GCentry gcname
344 = StJump (StCLbl (mkRtsGCEntryLabel gcname))
345 -- | otherwise -- it's in a different DLL
346 -- = StJump (StInd PtrRep (StLitLbl True sdoc))
348 gc_chk (StInt n) = mkStJump_to_GCentry ("stg_chk_" ++ show n)
349 gc_enter (StInt n) = mkStJump_to_GCentry ("stg_gc_enter_" ++ show n)
350 gc_seq (StInt n) = mkStJump_to_GCentry ("stg_gc_seq_" ++ show n)
351 gc_noregs = mkStJump_to_GCentry "stg_gc_noregs"
352 gc_unpt_r1 = mkStJump_to_GCentry "stg_gc_unpt_r1"
353 gc_unbx_r1 = mkStJump_to_GCentry "stg_gc_unbx_r1"
354 gc_f1 = mkStJump_to_GCentry "stg_gc_f1"
355 gc_d1 = mkStJump_to_GCentry "stg_gc_d1"
356 gc_gen = mkStJump_to_GCentry "stg_gen_chk"
357 gc_ut (StInt p) (StInt np)
358 = mkStJump_to_GCentry ("stg_gc_ut_" ++ show p