2 % (c) The AQUA Project, Glasgow University, 1993-1998
6 module StixPrim ( primCode, amodeToStix, amodeToStix' ) where
8 #include "HsVersions.h"
15 import AbsCSyn hiding ( spRel )
16 import AbsCUtils ( getAmodeRep, mixedTypeLocn )
17 import SMRep ( fixedHdrSize )
18 import Literal ( Literal(..), word2IntLit )
19 import CallConv ( cCallConv )
20 import PrimOp ( PrimOp(..), CCall(..), CCallTarget(..) )
21 import PrimRep ( PrimRep(..), isFloatingRep )
22 import UniqSupply ( returnUs, thenUs, getUniqueUs, UniqSM )
23 import Constants ( mIN_INTLIKE, uF_UPDATEE, bLOCK_SIZE )
24 import CLabel ( mkIntlikeClosureLabel, mkCharlikeClosureLabel,
25 mkMAP_FROZEN_infoLabel, mkForeignLabel )
28 import Char ( ord, isAlpha, isDigit )
33 The main honcho here is primCode, which handles the guts of COpStmts.
37 :: [CAddrMode] -- results
39 -> [CAddrMode] -- args
40 -> UniqSM StixTreeList
43 First, the dreaded @ccall@. We can't handle @casm@s.
45 Usually, this compiles to an assignment, but when the left-hand side
46 is empty, we just perform the call and ignore the result.
48 btw Why not let programmer use casm to provide assembly code instead
51 The (MP) integer operations are a true nightmare. Since we don't have
52 a convenient abstract way of allocating temporary variables on the (C)
53 stack, we use the space just below HpLim for the @MP_INT@ structures,
54 and modify our heap check accordingly.
57 -- NB: ordering of clauses somewhere driven by
58 -- the desire to getting sane patt-matching behavior
59 primCode res@[sr,dr] IntegerNegOp arg@[sa,da]
60 = gmpNegate (sr,dr) (sa,da)
62 primCode [res] IntegerCmpOp args@[sa1,da1, sa2,da2]
63 = gmpCompare res (sa1,da1, sa2,da2)
65 primCode [res] IntegerCmpIntOp args@[sa1,da1,ai]
66 = gmpCompareInt res (sa1,da1,ai)
68 primCode [res] Integer2IntOp arg@[sa,da]
69 = gmpInteger2Int res (sa,da)
71 primCode [res] Integer2WordOp arg@[sa,da]
72 = gmpInteger2Word res (sa,da)
74 primCode [res] Int2AddrOp [arg]
75 = simpleCoercion AddrRep res arg
77 primCode [res] Addr2IntOp [arg]
78 = simpleCoercion IntRep res arg
80 primCode [res] Int2WordOp [arg]
81 = simpleCoercion IntRep{-WordRep?-} res arg
83 primCode [res] Word2IntOp [arg]
84 = simpleCoercion IntRep res arg
88 primCode [res] SameMutableArrayOp args
90 compare = StPrim AddrEqOp (map amodeToStix args)
91 assign = StAssign IntRep (amodeToStix res) compare
93 returnUs (\xs -> assign : xs)
95 primCode res@[_] SameMutableByteArrayOp args
96 = primCode res SameMutableArrayOp args
98 primCode res@[_] SameMutVarOp args
99 = primCode res SameMutableArrayOp args
101 primCode res@[_] SameMVarOp args
102 = primCode res SameMutableArrayOp args
105 Freezing an array of pointers is a double assignment. We fix the
106 header of the ``new'' closure because the lhs is probably a better
107 addressing mode for the indirection (most likely, it's a VanillaReg).
111 primCode [lhs] UnsafeFreezeArrayOp [rhs]
113 lhs' = amodeToStix lhs
114 rhs' = amodeToStix rhs
115 header = StInd PtrRep lhs'
116 assign = StAssign PtrRep lhs' rhs'
117 freeze = StAssign PtrRep header mutArrPtrsFrozen_info
119 returnUs (\xs -> assign : freeze : xs)
121 primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
122 = simpleCoercion PtrRep lhs rhs
125 Returning the size of (mutable) byte arrays is just
126 an indexing operation.
129 primCode [lhs] SizeofByteArrayOp [rhs]
131 lhs' = amodeToStix lhs
132 rhs' = amodeToStix rhs
133 sz = StIndex IntRep rhs' fixedHS
134 assign = StAssign IntRep lhs' (StInd IntRep sz)
136 returnUs (\xs -> assign : xs)
138 primCode [lhs] SizeofMutableByteArrayOp [rhs]
140 lhs' = amodeToStix lhs
141 rhs' = amodeToStix rhs
142 sz = StIndex IntRep rhs' fixedHS
143 assign = StAssign IntRep lhs' (StInd IntRep sz)
145 returnUs (\xs -> assign : xs)
149 Most other array primitives translate to simple indexing.
152 primCode lhs@[_] IndexArrayOp args
153 = primCode lhs ReadArrayOp args
155 primCode [lhs] ReadArrayOp [obj, ix]
157 lhs' = amodeToStix lhs
158 obj' = amodeToStix obj
160 base = StIndex IntRep obj' arrPtrsHS
161 assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
163 returnUs (\xs -> assign : xs)
165 primCode [] WriteArrayOp [obj, ix, v]
167 obj' = amodeToStix obj
170 base = StIndex IntRep obj' arrPtrsHS
171 assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
173 returnUs (\xs -> assign : xs)
175 primCode lhs@[_] (IndexByteArrayOp pk) args
176 = primCode lhs (ReadByteArrayOp pk) args
178 -- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
180 primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
182 lhs' = amodeToStix lhs
183 obj' = amodeToStix obj
185 base = StIndex IntRep obj' arrWordsHS
186 assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
188 returnUs (\xs -> assign : xs)
190 primCode lhs@[_] (ReadOffAddrOp pk) args
191 = primCode lhs (IndexOffAddrOp pk) args
193 primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
195 lhs' = amodeToStix lhs
196 obj' = amodeToStix obj
198 assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
200 returnUs (\xs -> assign : xs)
202 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
204 lhs' = amodeToStix lhs
205 obj' = amodeToStix obj
207 obj'' = StIndex AddrRep obj' fixedHS
208 assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
210 returnUs (\xs -> assign : xs)
212 primCode [] (WriteOffAddrOp pk) [obj, ix, v]
214 obj' = amodeToStix obj
217 assign = StAssign pk (StInd pk (StIndex pk obj' ix')) v'
219 returnUs (\xs -> assign : xs)
221 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
223 obj' = amodeToStix obj
226 base = StIndex IntRep obj' arrWordsHS
227 assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
229 returnUs (\xs -> assign : xs)
231 primCode [] WriteForeignObjOp [obj, v]
233 obj' = amodeToStix obj
235 obj'' = StIndex AddrRep obj' (StInt 4711) -- fixedHS
236 assign = StAssign AddrRep (StInd AddrRep obj'') v'
238 returnUs (\xs -> assign : xs)
241 ToDo: saving/restoring of volatile regs around ccalls.
244 primCode lhs (CCallOp (CCall (StaticTarget fn) is_asm may_gc cconv)) rhs
245 | is_asm = error "ERROR: Native code generator can't handle casm"
246 | not may_gc = returnUs (\xs -> ccall : xs)
248 save_thread_state `thenUs` \ save ->
249 load_thread_state `thenUs` \ load ->
250 getUniqueUs `thenUs` \ uniq ->
252 id = StReg (StixTemp uniq IntRep)
254 suspend = StAssign IntRep id
255 (StCall SLIT("suspendThread") cconv IntRep [stgBaseReg])
256 resume = StCall SLIT("resumeThread") cconv VoidRep [id]
258 returnUs (\xs -> save (suspend : ccall : resume : load xs))
261 args = map amodeCodeForCCall rhs
262 amodeCodeForCCall x =
263 let base = amodeToStix' x
265 case getAmodeRep x of
266 ArrayRep -> StIndex PtrRep base arrPtrsHS
267 ByteArrayRep -> StIndex IntRep base arrWordsHS
268 ForeignObjRep -> StIndex PtrRep base fixedHS
272 [] -> StCall fn cconv VoidRep args
274 let lhs' = amodeToStix lhs
275 pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
277 StAssign pk lhs' (StCall fn cconv pk args)
280 DataToTagOp won't work for 64-bit archs, as it is.
283 primCode [lhs] DataToTagOp [arg]
284 = let lhs' = amodeToStix lhs
285 arg' = amodeToStix arg
286 infoptr = StInd PtrRep arg'
287 word_32 = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
288 masked_le32 = StPrim SrlOp [word_32, StInt 16]
289 masked_be32 = StPrim AndOp [word_32, StInt 65535]
290 #ifdef WORDS_BIGENDIAN
295 assign = StAssign IntRep lhs' masked
297 returnUs (\xs -> assign : xs)
300 MutVars are pretty simple.
301 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
304 primCode [] WriteMutVarOp [aa,vv]
305 = let aa_s = amodeToStix aa
306 vv_s = amodeToStix vv
307 var_field = StIndex PtrRep aa_s fixedHS
308 assign = StAssign PtrRep (StInd PtrRep var_field) vv_s
310 returnUs (\xs -> assign : xs)
312 primCode [rr] ReadMutVarOp [aa]
313 = let aa_s = amodeToStix aa
314 rr_s = amodeToStix rr
315 var_field = StIndex PtrRep aa_s fixedHS
316 assign = StAssign PtrRep rr_s (StInd PtrRep var_field)
318 returnUs (\xs -> assign : xs)
321 Now the more mundane operations.
326 lhs' = map amodeToStix lhs
327 rhs' = map amodeToStix' rhs
328 pk = getAmodeRep (head lhs)
330 returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
338 -> UniqSM StixTreeList
340 simpleCoercion pk lhs rhs
341 = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
344 Here we try to rewrite primitives into a form the code generator can
345 understand. Any primitives not handled here must be handled at the
346 level of the specific code generator.
350 :: PrimRep -- Rep of first destination
351 -> [StixTree] -- Destinations
357 Now look for something more conventional.
360 simplePrim pk [lhs] op rest = StAssign pk lhs (StPrim op rest)
361 simplePrim pk as op bs = simplePrim_error op
364 = 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")
367 %---------------------------------------------------------------------
369 Here we generate the Stix code for CAddrModes.
371 When a character is fetched from a mixed type location, we have to do
372 an extra cast. This is reflected in amodeCode', which is for rhs
373 amodes that might possibly need the extra cast.
376 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
378 amodeToStix'{-'-} am@(CVal rr CharRep)
379 | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
380 | otherwise = amodeToStix am
382 amodeToStix' am = amodeToStix am
385 amodeToStix am@(CVal rr CharRep)
387 = StInd IntRep (amodeToStix (CAddr rr))
389 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
391 amodeToStix (CAddr (SpRel off))
392 = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
394 amodeToStix (CAddr (HpRel off))
395 = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
397 amodeToStix (CAddr (NodeRel off))
398 = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
400 amodeToStix (CAddr (CIndex base off pk))
401 = StIndex pk (amodeToStix base) (amodeToStix off)
403 amodeToStix (CReg magic) = StReg (StixMagicId magic)
404 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
406 amodeToStix (CLbl lbl _) = StCLbl lbl
408 -- For CharLike and IntLike, we attempt some trivial constant-folding here.
410 amodeToStix (CCharLike (CLit (MachChar c)))
411 = StIndex CharRep cHARLIKE_closure (StInt (toInteger off))
413 off = charLikeSize * ord c
415 amodeToStix (CCharLike x)
416 = StIndex CharRep cHARLIKE_closure off
418 off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
420 amodeToStix (CIntLike (CLit (MachInt i)))
421 = StIndex CharRep{-yes,really-} iNTLIKE_closure (StInt (toInteger off))
423 off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
425 amodeToStix (CIntLike x)
428 amodeToStix (CLit core)
430 MachChar c -> StInt (toInteger (ord c))
431 MachStr s -> StString s
432 MachAddr a -> StInt a
434 MachWord w -> case word2IntLit core of MachInt iw -> StInt iw
435 MachLitLit s _ -> trace ("\nnativeGen WARNING: Reference to C entity `"
436 ++ (_UNPK_ s) ++ "' cannot be reliably compiled."
437 ++ "\n\t\t It may well crash your program."
438 ++ "\n\t\t Workaround: compile via C (use -fvia-C).\n"
440 (litLitToStix (_UNPK_ s))
441 MachFloat d -> StDouble d
442 MachDouble d -> StDouble d
443 _ -> panic "amodeToStix:core literal"
445 amodeToStix (CLitLit s _)
446 = litLitToStix (_UNPK_ s)
448 amodeToStix (CMacroExpr _ macro [arg])
450 ENTRY_CODE -> amodeToStix arg
451 ARG_TAG -> amodeToStix arg -- just an integer no. of words
453 #ifdef WORDS_BIGENDIAN
455 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
456 (StInt (toInteger (-1)))),
460 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
461 (StInt (toInteger (-1)))),
465 -> StInd PtrRep (StIndex PtrRep (amodeToStix arg)
466 (StInt (toInteger uF_UPDATEE)))
468 | all is_id nm = StCLbl (mkForeignLabel (_PK_ nm) False{-ToDo: dynamic-})
469 | otherwise = error ("\nlitLitToStix: can't handle `" ++ nm ++ "'\n"
470 ++ "suggested workaround: use flag -fvia-C\n")
472 where is_id c = isAlpha c || isDigit c || c == '_'
475 Sizes of the CharLike and IntLike closures that are arranged as arrays
476 in the data segment. (These are in bytes.)
479 -- The INTLIKE base pointer
481 iNTLIKE_closure :: StixTree
482 iNTLIKE_closure = StCLbl mkIntlikeClosureLabel
486 cHARLIKE_closure :: StixTree
487 cHARLIKE_closure = StCLbl mkCharlikeClosureLabel
489 mutArrPtrsFrozen_info = StCLbl mkMAP_FROZEN_infoLabel
491 -- these are the sizes of charLike and intLike closures, in _bytes_.
492 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
493 intLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
499 = getUniqueUs `thenUs` \tso_uq ->
500 let tso = StReg (StixTemp tso_uq ThreadIdRep) in
502 StAssign ThreadIdRep tso stgCurrentTSO :
504 (StInd PtrRep (StPrim IntAddOp
505 [tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))]))
508 (StInd PtrRep (StPrim IntAddOp
509 [tso, StInt (toInteger (TSO_SU*BYTES_PER_WORD))]))
512 (StInd PtrRep (StPrim IntAddOp
513 [tso, StInt (toInteger (TSO_SPLIM*BYTES_PER_WORD))]))
516 (StInd PtrRep (StPrim IntAddOp
518 StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))]))
519 (StPrim IntAddOp [stgHp, StInt (toInteger (1 * BYTES_PER_WORD))]) :
524 = getUniqueUs `thenUs` \tso_uq ->
525 let tso = StReg (StixTemp tso_uq ThreadIdRep) in
527 StAssign ThreadIdRep tso stgCurrentTSO :
528 StAssign PtrRep stgSp
529 (StInd PtrRep (StPrim IntAddOp
530 [tso, StInt (toInteger (TSO_SP*BYTES_PER_WORD))])) :
531 StAssign PtrRep stgSu
532 (StInd PtrRep (StPrim IntAddOp
533 [tso, StInt (toInteger (TSO_SU*BYTES_PER_WORD))])) :
534 StAssign PtrRep stgSpLim
535 (StInd PtrRep (StPrim IntAddOp
536 [tso, StInt (toInteger (TSO_SPLIM*BYTES_PER_WORD))])) :
537 StAssign PtrRep stgHp
539 StInd PtrRep (StPrim IntAddOp
541 StInt (toInteger (BDESCR_FREE * BYTES_PER_WORD))]),
542 StInt (toInteger (1 * BYTES_PER_WORD))
544 StAssign PtrRep stgHpLim
546 StInd PtrRep (StPrim IntAddOp
548 StInt (toInteger (BDESCR_START * BYTES_PER_WORD))]),
549 StInt (toInteger (bLOCK_SIZE - (1 * BYTES_PER_WORD)))