2 % (c) The AQUA Project, Glasgow University, 1993-1998
6 module StixPrim ( primCode, amodeToStix, amodeToStix' ) where
8 #include "HsVersions.h"
14 import AbsCSyn hiding ( spRel )
15 import AbsCUtils ( getAmodeRep, mixedTypeLocn )
16 import SMRep ( fixedHdrSize )
17 import Literal ( Literal(..), word2IntLit )
18 import PrimOp ( PrimOp(..), CCall(..), CCallTarget(..) )
19 import PrimRep ( PrimRep(..), isFloatingRep )
20 import UniqSupply ( returnUs, thenUs, getUniqueUs, UniqSM )
21 import Constants ( mIN_INTLIKE, uF_UPDATEE, bLOCK_SIZE )
22 import CLabel ( mkIntlikeClosureLabel, mkCharlikeClosureLabel,
23 mkMAP_FROZEN_infoLabel, mkForeignLabel )
26 import Char ( ord, isAlpha, isDigit )
31 The main honcho here is primCode, which handles the guts of COpStmts.
35 :: [CAddrMode] -- results
37 -> [CAddrMode] -- args
38 -> UniqSM StixTreeList
41 First, the dreaded @ccall@. We can't handle @casm@s.
43 Usually, this compiles to an assignment, but when the left-hand side
44 is empty, we just perform the call and ignore the result.
46 btw Why not let programmer use casm to provide assembly code instead
49 The (MP) integer operations are a true nightmare. Since we don't have
50 a convenient abstract way of allocating temporary variables on the (C)
51 stack, we use the space just below HpLim for the @MP_INT@ structures,
52 and modify our heap check accordingly.
55 -- NB: ordering of clauses somewhere driven by
56 -- the desire to getting sane patt-matching behavior
57 primCode res@[sr,dr] IntegerNegOp arg@[sa,da]
58 = gmpNegate (sr,dr) (sa,da)
60 primCode [res] IntegerCmpOp args@[sa1,da1, sa2,da2]
61 = gmpCompare res (sa1,da1, sa2,da2)
63 primCode [res] IntegerCmpIntOp args@[sa1,da1,ai]
64 = gmpCompareInt res (sa1,da1,ai)
66 primCode [res] Integer2IntOp arg@[sa,da]
67 = gmpInteger2Int res (sa,da)
69 primCode [res] Integer2WordOp arg@[sa,da]
70 = gmpInteger2Word res (sa,da)
72 primCode [res] Int2AddrOp [arg]
73 = simpleCoercion AddrRep res arg
75 primCode [res] Addr2IntOp [arg]
76 = simpleCoercion IntRep res arg
78 primCode [res] Int2WordOp [arg]
79 = simpleCoercion IntRep{-WordRep?-} res arg
81 primCode [res] Word2IntOp [arg]
82 = simpleCoercion IntRep res arg
86 primCode [res] SameMutableArrayOp args
88 compare = StPrim AddrEqOp (map amodeToStix args)
89 assign = StAssign IntRep (amodeToStix res) compare
91 returnUs (\xs -> assign : xs)
93 primCode res@[_] SameMutableByteArrayOp args
94 = primCode res SameMutableArrayOp args
96 primCode res@[_] SameMutVarOp args
97 = primCode res SameMutableArrayOp args
99 primCode res@[_] SameMVarOp args
100 = primCode res SameMutableArrayOp args
103 Freezing an array of pointers is a double assignment. We fix the
104 header of the ``new'' closure because the lhs is probably a better
105 addressing mode for the indirection (most likely, it's a VanillaReg).
109 primCode [lhs] UnsafeFreezeArrayOp [rhs]
111 lhs' = amodeToStix lhs
112 rhs' = amodeToStix rhs
113 header = StInd PtrRep lhs'
114 assign = StAssign PtrRep lhs' rhs'
115 freeze = StAssign PtrRep header mutArrPtrsFrozen_info
117 returnUs (\xs -> assign : freeze : xs)
119 primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
120 = simpleCoercion PtrRep lhs rhs
123 Returning the size of (mutable) byte arrays is just
124 an indexing operation.
127 primCode [lhs] SizeofByteArrayOp [rhs]
129 lhs' = amodeToStix lhs
130 rhs' = amodeToStix rhs
131 sz = StIndex IntRep rhs' fixedHS
132 assign = StAssign IntRep lhs' (StInd IntRep sz)
134 returnUs (\xs -> assign : xs)
136 primCode [lhs] SizeofMutableByteArrayOp [rhs]
138 lhs' = amodeToStix lhs
139 rhs' = amodeToStix rhs
140 sz = StIndex IntRep rhs' fixedHS
141 assign = StAssign IntRep lhs' (StInd IntRep sz)
143 returnUs (\xs -> assign : xs)
147 Most other array primitives translate to simple indexing.
150 primCode lhs@[_] IndexArrayOp args
151 = primCode lhs ReadArrayOp args
153 primCode [lhs] ReadArrayOp [obj, ix]
155 lhs' = amodeToStix lhs
156 obj' = amodeToStix obj
158 base = StIndex IntRep obj' arrPtrsHS
159 assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
161 returnUs (\xs -> assign : xs)
163 primCode [] WriteArrayOp [obj, ix, v]
165 obj' = amodeToStix obj
168 base = StIndex IntRep obj' arrPtrsHS
169 assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
171 returnUs (\xs -> assign : xs)
173 primCode lhs@[_] (IndexByteArrayOp pk) args
174 = primCode lhs (ReadByteArrayOp pk) args
176 -- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
178 primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
180 lhs' = amodeToStix lhs
181 obj' = amodeToStix obj
183 base = StIndex IntRep obj' arrWordsHS
184 assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
186 returnUs (\xs -> assign : xs)
188 primCode lhs@[_] (ReadOffAddrOp pk) args
189 = primCode lhs (IndexOffAddrOp pk) args
191 primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
193 lhs' = amodeToStix lhs
194 obj' = amodeToStix obj
196 assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
198 returnUs (\xs -> assign : xs)
200 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
202 lhs' = amodeToStix lhs
203 obj' = amodeToStix obj
205 obj'' = StIndex AddrRep obj' fixedHS
206 assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
208 returnUs (\xs -> assign : xs)
210 primCode [] (WriteOffAddrOp pk) [obj, ix, v]
212 obj' = amodeToStix obj
215 assign = StAssign pk (StInd pk (StIndex pk obj' ix')) v'
217 returnUs (\xs -> assign : xs)
219 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
221 obj' = amodeToStix obj
224 base = StIndex IntRep obj' arrWordsHS
225 assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
227 returnUs (\xs -> assign : xs)
229 primCode [] WriteForeignObjOp [obj, v]
231 obj' = amodeToStix obj
233 obj'' = StIndex AddrRep obj' (StInt 4711) -- fixedHS
234 assign = StAssign AddrRep (StInd AddrRep obj'') v'
236 returnUs (\xs -> assign : xs)
239 ToDo: saving/restoring of volatile regs around ccalls.
242 primCode lhs (CCallOp (CCall (StaticTarget fn) is_asm may_gc cconv)) rhs
243 | is_asm = error "ERROR: Native code generator can't handle casm"
244 | not may_gc = returnUs (\xs -> ccall : xs)
246 save_thread_state `thenUs` \ save ->
247 load_thread_state `thenUs` \ load ->
248 getUniqueUs `thenUs` \ uniq ->
250 id = StReg (StixTemp uniq IntRep)
252 suspend = StAssign IntRep id
253 (StCall SLIT("suspendThread") cconv IntRep [stgBaseReg])
254 resume = StCall SLIT("resumeThread") cconv VoidRep [id]
256 returnUs (\xs -> save (suspend : ccall : resume : load xs))
259 args = map amodeCodeForCCall rhs
260 amodeCodeForCCall x =
261 let base = amodeToStix' x
263 case getAmodeRep x of
264 ArrayRep -> StIndex PtrRep base arrPtrsHS
265 ByteArrayRep -> StIndex IntRep base arrWordsHS
266 ForeignObjRep -> StIndex PtrRep base fixedHS
270 [] -> StCall fn cconv VoidRep args
272 let lhs' = amodeToStix lhs
273 pk = case getAmodeRep lhs of
275 DoubleRep -> DoubleRep
278 StAssign pk lhs' (StCall fn cconv pk args)
281 DataToTagOp won't work for 64-bit archs, as it is.
284 primCode [lhs] DataToTagOp [arg]
285 = let lhs' = amodeToStix lhs
286 arg' = amodeToStix arg
287 infoptr = StInd PtrRep arg'
288 word_32 = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
289 masked_le32 = StPrim SrlOp [word_32, StInt 16]
290 masked_be32 = StPrim AndOp [word_32, StInt 65535]
291 #ifdef WORDS_BIGENDIAN
296 assign = StAssign IntRep lhs' masked
298 returnUs (\xs -> assign : xs)
301 MutVars are pretty simple.
302 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
305 primCode [] WriteMutVarOp [aa,vv]
306 = let aa_s = amodeToStix aa
307 vv_s = amodeToStix vv
308 var_field = StIndex PtrRep aa_s fixedHS
309 assign = StAssign PtrRep (StInd PtrRep var_field) vv_s
311 returnUs (\xs -> assign : xs)
313 primCode [rr] ReadMutVarOp [aa]
314 = let aa_s = amodeToStix aa
315 rr_s = amodeToStix rr
316 var_field = StIndex PtrRep aa_s fixedHS
317 assign = StAssign PtrRep rr_s (StInd PtrRep var_field)
319 returnUs (\xs -> assign : xs)
322 Now the more mundane operations.
327 lhs' = map amodeToStix lhs
328 rhs' = map amodeToStix' rhs
329 pk = getAmodeRep (head lhs)
331 returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
339 -> UniqSM StixTreeList
341 simpleCoercion pk lhs rhs
342 = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
345 Here we try to rewrite primitives into a form the code generator can
346 understand. Any primitives not handled here must be handled at the
347 level of the specific code generator.
351 :: PrimRep -- Rep of first destination
352 -> [StixTree] -- Destinations
358 Now look for something more conventional.
361 simplePrim pk [lhs] op rest = StAssign pk lhs (StPrim op rest)
362 simplePrim pk as op bs = simplePrim_error op
365 = error ("ERROR: primitive operation `"++show op++"'cannot be handled\nby the native-code generator. Workaround: use -fvia-C.\n(Perhaps you should report it as a GHC bug, also.)\n")
368 %---------------------------------------------------------------------
370 Here we generate the Stix code for CAddrModes.
372 When a character is fetched from a mixed type location, we have to do
373 an extra cast. This is reflected in amodeCode', which is for rhs
374 amodes that might possibly need the extra cast.
377 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
379 amodeToStix'{-'-} am@(CVal rr CharRep)
380 | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
381 | otherwise = amodeToStix am
383 amodeToStix' am = amodeToStix am
386 amodeToStix am@(CVal rr CharRep)
388 = StInd IntRep (amodeToStix (CAddr rr))
390 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
392 amodeToStix (CAddr (SpRel off))
393 = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
395 amodeToStix (CAddr (HpRel off))
396 = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
398 amodeToStix (CAddr (NodeRel off))
399 = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
401 amodeToStix (CAddr (CIndex base off pk))
402 = StIndex pk (amodeToStix base) (amodeToStix off)
404 amodeToStix (CReg magic) = StReg (StixMagicId magic)
405 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
407 amodeToStix (CLbl lbl _) = StCLbl lbl
409 -- For CharLike and IntLike, we attempt some trivial constant-folding here.
411 amodeToStix (CCharLike (CLit (MachChar c)))
412 = StIndex CharRep cHARLIKE_closure (StInt (toInteger off))
414 off = charLikeSize * ord c
416 amodeToStix (CCharLike x)
417 = StIndex CharRep cHARLIKE_closure off
419 off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
421 amodeToStix (CIntLike (CLit (MachInt i)))
422 = StIndex CharRep{-yes,really-} iNTLIKE_closure (StInt (toInteger off))
424 off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
426 amodeToStix (CIntLike x)
429 amodeToStix (CLit core)
431 MachChar c -> StInt (toInteger (ord c))
432 MachStr s -> StString s
433 MachAddr a -> StInt a
435 MachWord w -> case word2IntLit core of MachInt iw -> StInt iw
436 MachLitLit s _ -> litLitErr
437 MachLabel l -> StCLbl (mkForeignLabel l False{-ToDo: dynamic-})
438 MachFloat d -> StFloat d
439 MachDouble d -> StDouble d
440 _ -> panic "amodeToStix:core literal"
442 amodeToStix (CMacroExpr _ macro [arg])
444 ENTRY_CODE -> amodeToStix arg
445 ARG_TAG -> amodeToStix arg -- just an integer no. of words
447 #ifdef WORDS_BIGENDIAN
449 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
450 (StInt (toInteger (-1)))),
454 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
455 (StInt (toInteger (-1)))),
459 -> StInd PtrRep (StIndex PtrRep (amodeToStix arg)
460 (StInt (toInteger uF_UPDATEE)))
463 panic "native code generator can't compile lit-lits, use -fvia-C"
466 Sizes of the CharLike and IntLike closures that are arranged as arrays
467 in the data segment. (These are in bytes.)
470 -- The INTLIKE base pointer
472 iNTLIKE_closure :: StixTree
473 iNTLIKE_closure = StCLbl mkIntlikeClosureLabel
477 cHARLIKE_closure :: StixTree
478 cHARLIKE_closure = StCLbl mkCharlikeClosureLabel
480 mutArrPtrsFrozen_info = StCLbl mkMAP_FROZEN_infoLabel
482 -- these are the sizes of charLike and intLike closures, in _bytes_.
483 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
484 intLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
490 = getUniqueUs `thenUs` \tso_uq ->
491 let tso = StReg (StixTemp tso_uq ThreadIdRep) in
493 StAssign ThreadIdRep tso stgCurrentTSO :
495 (StInd PtrRep (StPrim IntAddOp
496 [tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))]))
499 (StInd PtrRep (StPrim IntAddOp
500 [tso, StInt (toInteger (TSO_SU*BYTES_PER_WORD))]))
503 (StInd PtrRep (StPrim IntAddOp
504 [tso, StInt (toInteger (TSO_SPLIM*BYTES_PER_WORD))]))
507 (StInd PtrRep (StPrim IntAddOp
509 StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))]))
510 (StPrim IntAddOp [stgHp, StInt (toInteger (1 * BYTES_PER_WORD))]) :
515 = getUniqueUs `thenUs` \tso_uq ->
516 let tso = StReg (StixTemp tso_uq ThreadIdRep) in
518 StAssign ThreadIdRep tso stgCurrentTSO :
519 StAssign PtrRep stgSp
520 (StInd PtrRep (StPrim IntAddOp
521 [tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))])) :
522 StAssign PtrRep stgSu
523 (StInd PtrRep (StPrim IntAddOp
524 [tso, StInt (toInteger (TSO_SU*BYTES_PER_WORD))])) :
525 StAssign PtrRep stgSpLim
526 (StInd PtrRep (StPrim IntAddOp
527 [tso, StInt (toInteger (TSO_SPLIM*BYTES_PER_WORD))])) :
528 StAssign PtrRep stgHp
530 StInd PtrRep (StPrim IntAddOp
532 StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))]),
533 StInt (toInteger (1 * BYTES_PER_WORD))
535 StAssign PtrRep stgHpLim
537 StInd PtrRep (StPrim IntAddOp
539 StInt (toInteger (BDESCR_START * BYTES_PER_WORD))]),
540 StInt (toInteger (bLOCK_SIZE - (1 * BYTES_PER_WORD)))