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 Constants ( uF_UPDATEE )
18 import SMRep ( fixedHdrSize )
19 import Literal ( Literal(..), word2IntLit )
20 import CallConv ( cCallConv )
21 import PrimOp ( PrimOp(..), CCall(..), CCallTarget(..) )
22 import PrimRep ( PrimRep(..), isFloatingRep )
23 import UniqSupply ( returnUs, thenUs, getUniqueUs, UniqSM )
24 import Constants ( mIN_INTLIKE )
30 The main honcho here is primCode, which handles the guts of COpStmts.
34 :: [CAddrMode] -- results
36 -> [CAddrMode] -- args
37 -> UniqSM StixTreeList
40 First, the dreaded @ccall@. We can't handle @casm@s.
42 Usually, this compiles to an assignment, but when the left-hand side
43 is empty, we just perform the call and ignore the result.
45 btw Why not let programmer use casm to provide assembly code instead
48 The (MP) integer operations are a true nightmare. Since we don't have
49 a convenient abstract way of allocating temporary variables on the (C)
50 stack, we use the space just below HpLim for the @MP_INT@ structures,
51 and modify our heap check accordingly.
54 -- NB: ordering of clauses somewhere driven by
55 -- the desire to getting sane patt-matching behavior
56 primCode res@[sr,dr] IntegerNegOp arg@[sa,da]
57 = gmpNegate (sr,dr) (sa,da)
59 primCode [res] IntegerCmpOp args@[sa1,da1, sa2,da2]
60 = gmpCompare res (sa1,da1, sa2,da2)
62 primCode [res] IntegerCmpIntOp args@[sa1,da1,ai]
63 = gmpCompareInt res (sa1,da1,ai)
65 primCode [res] Integer2IntOp arg@[sa,da]
66 = gmpInteger2Int res (sa,da)
68 primCode [res] Integer2WordOp arg@[sa,da]
69 = gmpInteger2Word res (sa,da)
71 primCode [res] Int2AddrOp [arg]
72 = simpleCoercion AddrRep res arg
74 primCode [res] Addr2IntOp [arg]
75 = simpleCoercion IntRep res arg
77 primCode [res] Int2WordOp [arg]
78 = simpleCoercion IntRep{-WordRep?-} res arg
80 primCode [res] Word2IntOp [arg]
81 = simpleCoercion IntRep res arg
85 primCode [res] SameMutableArrayOp args
87 compare = StPrim AddrEqOp (map amodeToStix args)
88 assign = StAssign IntRep (amodeToStix res) compare
90 returnUs (\xs -> assign : xs)
92 primCode res@[_] SameMutableByteArrayOp args
93 = primCode res SameMutableArrayOp args
95 primCode res@[_] SameMutVarOp args
96 = primCode res SameMutableArrayOp args
98 primCode res@[_] SameMVarOp args
99 = primCode res SameMutableArrayOp args
102 Freezing an array of pointers is a double assignment. We fix the
103 header of the ``new'' closure because the lhs is probably a better
104 addressing mode for the indirection (most likely, it's a VanillaReg).
108 primCode [lhs] UnsafeFreezeArrayOp [rhs]
110 lhs' = amodeToStix lhs
111 rhs' = amodeToStix rhs
112 header = StInd PtrRep lhs'
113 assign = StAssign PtrRep lhs' rhs'
114 freeze = StAssign PtrRep header mutArrPtrsFrozen_info
116 returnUs (\xs -> assign : freeze : xs)
118 primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
119 = simpleCoercion PtrRep lhs rhs
122 Returning the size of (mutable) byte arrays is just
123 an indexing operation.
126 primCode [lhs] SizeofByteArrayOp [rhs]
128 lhs' = amodeToStix lhs
129 rhs' = amodeToStix rhs
130 sz = StIndex IntRep rhs' fixedHS
131 assign = StAssign IntRep lhs' (StInd IntRep sz)
133 returnUs (\xs -> assign : xs)
135 primCode [lhs] SizeofMutableByteArrayOp [rhs]
137 lhs' = amodeToStix lhs
138 rhs' = amodeToStix rhs
139 sz = StIndex IntRep rhs' fixedHS
140 assign = StAssign IntRep lhs' (StInd IntRep sz)
142 returnUs (\xs -> assign : xs)
146 Most other array primitives translate to simple indexing.
149 primCode lhs@[_] IndexArrayOp args
150 = primCode lhs ReadArrayOp args
152 primCode [lhs] ReadArrayOp [obj, ix]
154 lhs' = amodeToStix lhs
155 obj' = amodeToStix obj
157 base = StIndex IntRep obj' arrPtrsHS
158 assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
160 returnUs (\xs -> assign : xs)
162 primCode [] WriteArrayOp [obj, ix, v]
164 obj' = amodeToStix obj
167 base = StIndex IntRep obj' arrPtrsHS
168 assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
170 returnUs (\xs -> assign : xs)
172 primCode lhs@[_] (IndexByteArrayOp pk) args
173 = primCode lhs (ReadByteArrayOp pk) args
175 -- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
177 primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
179 lhs' = amodeToStix lhs
180 obj' = amodeToStix obj
182 base = StIndex IntRep obj' arrWordsHS
183 assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
185 returnUs (\xs -> assign : xs)
187 primCode lhs@[_] (ReadOffAddrOp pk) args
188 = primCode lhs (IndexOffAddrOp pk) args
190 primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
192 lhs' = amodeToStix lhs
193 obj' = amodeToStix obj
195 assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
197 returnUs (\xs -> assign : xs)
199 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
201 lhs' = amodeToStix lhs
202 obj' = amodeToStix obj
204 obj'' = StIndex AddrRep obj' fixedHS
205 assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
207 returnUs (\xs -> assign : xs)
209 primCode [] (WriteOffAddrOp pk) [obj, ix, v]
211 obj' = amodeToStix obj
214 assign = StAssign pk (StInd pk (StIndex pk obj' ix')) v'
216 returnUs (\xs -> assign : xs)
218 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
220 obj' = amodeToStix obj
223 base = StIndex IntRep obj' arrWordsHS
224 assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
226 returnUs (\xs -> assign : xs)
228 primCode [] WriteForeignObjOp [obj, v]
230 obj' = amodeToStix obj
232 obj'' = StIndex AddrRep obj' (StInt 4711) -- fixedHS
233 assign = StAssign AddrRep (StInd AddrRep obj'') v'
235 returnUs (\xs -> assign : xs)
238 ToDo: saving/restoring of volatile regs around ccalls.
241 primCode lhs (CCallOp (CCall (StaticTarget fn) is_asm may_gc cconv)) rhs
242 | is_asm = error "ERROR: Native code generator can't handle casm"
243 | not may_gc = returnUs (\xs -> ccall : xs)
245 getUniqueUs `thenUs` \ uniq ->
247 id = StReg (StixTemp uniq IntRep)
248 suspend = StAssign IntRep id
249 (StCall SLIT("suspendThread") cconv IntRep [stgBaseReg])
250 resume = StCall SLIT("resumeThread") cconv VoidRep [id]
252 returnUs (\xs -> suspend : ccall : resume : xs)
255 args = map amodeCodeForCCall rhs
256 amodeCodeForCCall x =
257 let base = amodeToStix' x
259 case getAmodeRep x of
260 ArrayRep -> StIndex PtrRep base arrPtrsHS
261 ByteArrayRep -> StIndex IntRep base arrWordsHS
262 ForeignObjRep -> StIndex PtrRep base fixedHS
266 [] -> StCall fn cconv VoidRep args
268 let lhs' = amodeToStix lhs
269 pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
271 StAssign pk lhs' (StCall fn cconv pk args)
274 DataToTagOp won't work for 64-bit archs, as it is.
277 primCode [lhs] DataToTagOp [arg]
278 = let lhs' = amodeToStix lhs
279 arg' = amodeToStix arg
280 infoptr = StInd PtrRep arg'
281 word_32 = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
282 masked_le32 = StPrim SrlOp [word_32, StInt 16]
283 masked_be32 = StPrim AndOp [word_32, StInt 65535]
284 #ifdef WORDS_BIGENDIAN
289 assign = StAssign IntRep lhs' masked
291 returnUs (\xs -> assign : xs)
294 MutVars are pretty simple.
295 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
298 primCode [] WriteMutVarOp [aa,vv]
299 = let aa_s = amodeToStix aa
300 vv_s = amodeToStix vv
301 var_field = StIndex PtrRep aa_s fixedHS
302 assign = StAssign PtrRep (StInd PtrRep var_field) vv_s
304 returnUs (\xs -> assign : xs)
306 primCode [rr] ReadMutVarOp [aa]
307 = let aa_s = amodeToStix aa
308 rr_s = amodeToStix rr
309 var_field = StIndex PtrRep aa_s fixedHS
310 assign = StAssign PtrRep rr_s (StInd PtrRep var_field)
312 returnUs (\xs -> assign : xs)
315 Now the more mundane operations.
320 lhs' = map amodeToStix lhs
321 rhs' = map amodeToStix' rhs
322 pk = getAmodeRep (head lhs)
324 returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
332 -> UniqSM StixTreeList
334 simpleCoercion pk lhs rhs
335 = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
338 Here we try to rewrite primitives into a form the code generator can
339 understand. Any primitives not handled here must be handled at the
340 level of the specific code generator.
344 :: PrimRep -- Rep of first destination
345 -> [StixTree] -- Destinations
351 Now look for something more conventional.
354 simplePrim pk [lhs] op rest = StAssign pk lhs (StPrim op rest)
355 simplePrim pk as op bs = simplePrim_error op
358 = 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")
361 %---------------------------------------------------------------------
363 Here we generate the Stix code for CAddrModes.
365 When a character is fetched from a mixed type location, we have to do
366 an extra cast. This is reflected in amodeCode', which is for rhs
367 amodes that might possibly need the extra cast.
370 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
372 amodeToStix'{-'-} am@(CVal rr CharRep)
373 | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
374 | otherwise = amodeToStix am
376 amodeToStix' am = amodeToStix am
379 amodeToStix am@(CVal rr CharRep)
381 = StInd IntRep (amodeToStix (CAddr rr))
383 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
385 amodeToStix (CAddr (SpRel off))
386 = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
388 amodeToStix (CAddr (HpRel off))
389 = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
391 amodeToStix (CAddr (NodeRel off))
392 = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
394 amodeToStix (CAddr (CIndex base off pk))
395 = StIndex pk (amodeToStix base) (amodeToStix off)
397 amodeToStix (CReg magic) = StReg (StixMagicId magic)
398 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
400 amodeToStix (CLbl lbl _) = StCLbl lbl
402 -- For CharLike and IntLike, we attempt some trivial constant-folding here.
404 amodeToStix (CCharLike (CLit (MachChar c)))
405 = StLitLbl ((<>) (ptext SLIT("CHARLIKE_closure+")) (int off))
407 off = charLikeSize * ord c
409 amodeToStix (CCharLike x)
410 = StIndex CharRep charLike off
412 off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
414 amodeToStix (CIntLike (CLit (MachInt i)))
415 = StLitLbl ((<>) (ptext SLIT("INTLIKE_closure+")) (int off))
417 off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
419 amodeToStix (CIntLike x)
422 amodeToStix (CLit core)
424 MachChar c -> StInt (toInteger (ord c))
425 MachStr s -> StString s
426 MachAddr a -> StInt a
428 MachWord w -> case word2IntLit core of MachInt iw -> StInt iw
429 MachLitLit s _ -> litLitToStix (_UNPK_ s)
430 MachFloat d -> StDouble d
431 MachDouble d -> StDouble d
432 _ -> panic "amodeToStix:core literal"
434 amodeToStix (CLitLit s _)
435 = litLitToStix (_UNPK_ s)
437 amodeToStix (CMacroExpr _ macro [arg])
439 ENTRY_CODE -> amodeToStix arg
440 ARG_TAG -> amodeToStix arg -- just an integer no. of words
442 #ifdef WORDS_BIGENDIAN
444 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
445 (StInt (toInteger (-1)))),
449 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
450 (StInt (toInteger (-1)))),
454 -> StInd PtrRep (StIndex PtrRep (amodeToStix arg)
455 (StInt (toInteger uF_UPDATEE)))
457 -- GET_TAG(info_ptr) is supposed to be get_itbl(info_ptr)->srt_len,
458 -- which we've had to hand-code here.
460 litLitToStix :: String -> StixTree
463 "stdout" -> stixFor_stdout
464 "stderr" -> stixFor_stderr
465 "stdin" -> stixFor_stdin
466 other -> error ("\nlitLitToStix: can't handle `" ++ nm ++ "'\n"
467 ++ "suggested workaround: use flag -fvia-C\n")
470 Sizes of the CharLike and IntLike closures that are arranged as arrays
471 in the data segment. (These are in bytes.)
474 -- The INTLIKE base pointer
476 intLikePtr :: StixTree
478 intLikePtr = StInd PtrRep (sStLitLbl SLIT("INTLIKE_closure"))
484 charLike = sStLitLbl SLIT("CHARLIKE_closure")
486 -- Trees for the ErrorIOPrimOp
488 topClosure, errorIO :: StixTree
490 topClosure = StInd PtrRep (sStLitLbl SLIT("TopClosure"))
491 errorIO = StJump (StInd PtrRep (sStLitLbl SLIT("ErrorIO_innards")))
493 mutArrPtrsFrozen_info = sStLitLbl SLIT("MUT_ARR_PTRS_FROZEN_info")
495 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
496 intLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))