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, 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
96 Freezing an array of pointers is a double assignment. We fix the
97 header of the ``new'' closure because the lhs is probably a better
98 addressing mode for the indirection (most likely, it's a VanillaReg).
102 primCode [lhs] UnsafeFreezeArrayOp [rhs]
104 lhs' = amodeToStix lhs
105 rhs' = amodeToStix rhs
106 header = StInd PtrRep lhs'
107 assign = StAssign PtrRep lhs' rhs'
108 freeze = StAssign PtrRep header mutArrPtrsFrozen_info
110 returnUs (\xs -> assign : freeze : xs)
112 primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
113 = simpleCoercion PtrRep lhs rhs
116 Returning the size of (mutable) byte arrays is just
117 an indexing operation.
120 primCode [lhs] SizeofByteArrayOp [rhs]
122 lhs' = amodeToStix lhs
123 rhs' = amodeToStix rhs
124 sz = StIndex IntRep rhs' fixedHS
125 assign = StAssign IntRep lhs' (StInd IntRep sz)
127 returnUs (\xs -> assign : xs)
129 primCode [lhs] SizeofMutableByteArrayOp [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)
140 Most other array primitives translate to simple indexing.
143 primCode lhs@[_] IndexArrayOp args
144 = primCode lhs ReadArrayOp args
146 primCode [lhs] ReadArrayOp [obj, ix]
148 lhs' = amodeToStix lhs
149 obj' = amodeToStix obj
151 base = StIndex IntRep obj' arrPtrsHS
152 assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
154 returnUs (\xs -> assign : xs)
156 primCode [] WriteArrayOp [obj, ix, v]
158 obj' = amodeToStix obj
161 base = StIndex IntRep obj' arrPtrsHS
162 assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
164 returnUs (\xs -> assign : xs)
166 primCode lhs@[_] (IndexByteArrayOp pk) args
167 = primCode lhs (ReadByteArrayOp pk) args
169 -- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
171 primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
173 lhs' = amodeToStix lhs
174 obj' = amodeToStix obj
176 base = StIndex IntRep obj' arrWordsHS
177 assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
179 returnUs (\xs -> assign : xs)
181 primCode lhs@[_] (ReadOffAddrOp pk) args
182 = primCode lhs (IndexOffAddrOp pk) args
184 primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
186 lhs' = amodeToStix lhs
187 obj' = amodeToStix obj
189 assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
191 returnUs (\xs -> assign : xs)
193 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
195 lhs' = amodeToStix lhs
196 obj' = amodeToStix obj
198 obj'' = StIndex PtrRep obj' fixedHS
199 assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
201 returnUs (\xs -> assign : xs)
203 primCode [] (WriteOffAddrOp pk) [obj, ix, v]
205 obj' = amodeToStix obj
208 assign = StAssign pk (StInd pk (StIndex pk obj' ix')) v'
210 returnUs (\xs -> assign : xs)
212 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
214 obj' = amodeToStix obj
217 base = StIndex IntRep obj' arrWordsHS
218 assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
220 returnUs (\xs -> assign : xs)
224 --primCode lhs (CCallOp fn is_asm may_gc) rhs
225 primCode lhs (CCallOp (CCall (StaticTarget fn) is_asm may_gc cconv)) rhs
226 | is_asm = error "ERROR: Native code generator can't handle casm"
227 | may_gc = error "ERROR: Native code generator can't handle _ccall_GC_\n"
230 [] -> returnUs (\xs -> (StCall fn cconv VoidRep args) : xs)
232 let lhs' = amodeToStix lhs
233 pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
234 call = StAssign pk lhs' (StCall fn cconv pk args)
236 returnUs (\xs -> call : xs)
238 args = map amodeCodeForCCall rhs
239 amodeCodeForCCall x =
240 let base = amodeToStix' x
242 case getAmodeRep x of
243 ArrayRep -> StIndex PtrRep base arrPtrsHS
244 ByteArrayRep -> StIndex IntRep base arrWordsHS
245 ForeignObjRep -> StIndex PtrRep base fixedHS
249 DataToTagOp won't work for 64-bit archs, as it is.
252 primCode [lhs] DataToTagOp [arg]
253 = let lhs' = amodeToStix lhs
254 arg' = amodeToStix arg
255 infoptr = StInd PtrRep arg'
256 word_32 = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
257 masked_le32 = StPrim SrlOp [word_32, StInt 16]
258 masked_be32 = StPrim AndOp [word_32, StInt 65535]
259 #ifdef WORDS_BIGENDIAN
264 assign = StAssign IntRep lhs' masked
266 returnUs (\xs -> assign : xs)
269 MutVars are pretty simple.
270 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
273 primCode [] WriteMutVarOp [aa,vv]
274 = let aa_s = amodeToStix aa
275 vv_s = amodeToStix vv
276 var_field = StIndex PtrRep aa_s fixedHS
277 assign = StAssign PtrRep (StInd PtrRep var_field) vv_s
279 returnUs (\xs -> assign : xs)
281 primCode [rr] ReadMutVarOp [aa]
282 = let aa_s = amodeToStix aa
283 rr_s = amodeToStix rr
284 var_field = StIndex PtrRep aa_s fixedHS
285 assign = StAssign PtrRep rr_s (StInd PtrRep var_field)
287 returnUs (\xs -> assign : xs)
290 Now the more mundane operations.
295 lhs' = map amodeToStix lhs
296 rhs' = map amodeToStix' rhs
297 pk = getAmodeRep (head lhs)
299 returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
307 -> UniqSM StixTreeList
309 simpleCoercion pk lhs rhs
310 = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
313 Here we try to rewrite primitives into a form the code generator can
314 understand. Any primitives not handled here must be handled at the
315 level of the specific code generator.
319 :: PrimRep -- Rep of first destination
320 -> [StixTree] -- Destinations
326 Now look for something more conventional.
329 simplePrim pk [lhs] op rest = StAssign pk lhs (StPrim op rest)
330 simplePrim pk as op bs = simplePrim_error op
333 = 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")
336 %---------------------------------------------------------------------
338 Here we generate the Stix code for CAddrModes.
340 When a character is fetched from a mixed type location, we have to do
341 an extra cast. This is reflected in amodeCode', which is for rhs
342 amodes that might possibly need the extra cast.
345 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
347 amodeToStix'{-'-} am@(CVal rr CharRep)
348 | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
349 | otherwise = amodeToStix am
351 amodeToStix' am = amodeToStix am
354 amodeToStix am@(CVal rr CharRep)
356 = StInd IntRep (amodeToStix (CAddr rr))
358 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
360 amodeToStix (CAddr (SpRel off))
361 = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
363 amodeToStix (CAddr (HpRel off))
364 = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
366 amodeToStix (CAddr (NodeRel off))
367 = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
369 amodeToStix (CAddr (CIndex base off pk))
370 = StIndex pk (amodeToStix base) (amodeToStix off)
372 amodeToStix (CReg magic) = StReg (StixMagicId magic)
373 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
375 amodeToStix (CLbl lbl _) = StCLbl lbl
377 -- For CharLike and IntLike, we attempt some trivial constant-folding here.
379 amodeToStix (CCharLike (CLit (MachChar c)))
380 = StLitLbl ((<>) (ptext SLIT("CHARLIKE_closure+")) (int off))
382 off = charLikeSize * ord c
384 amodeToStix (CCharLike x)
385 = StIndex CharRep charLike off
387 off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
389 amodeToStix (CIntLike (CLit (MachInt i)))
390 = StLitLbl ((<>) (ptext SLIT("INTLIKE_closure+")) (int off))
392 off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
394 amodeToStix (CIntLike x)
397 amodeToStix (CLit core)
399 MachChar c -> StInt (toInteger (ord c))
400 MachStr s -> StString s
401 MachAddr a -> StInt a
403 MachWord w -> case word2IntLit core of MachInt iw -> StInt iw
404 MachLitLit s _ -> litLitToStix (_UNPK_ s)
405 MachFloat d -> StDouble d
406 MachDouble d -> StDouble d
407 _ -> panic "amodeToStix:core literal"
409 amodeToStix (CLitLit s _)
410 = litLitToStix (_UNPK_ s)
412 amodeToStix (CMacroExpr _ macro [arg])
414 ENTRY_CODE -> amodeToStix arg
415 ARG_TAG -> amodeToStix arg -- just an integer no. of words
417 #ifdef WORDS_BIGENDIAN
419 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
420 (StInt (toInteger (-1)))),
424 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
425 (StInt (toInteger (-1)))),
429 -> StInd PtrRep (StIndex PtrRep (amodeToStix arg)
430 (StInt (toInteger uF_UPDATEE)))
432 -- GET_TAG(info_ptr) is supposed to be get_itbl(info_ptr)->srt_len,
433 -- which we've had to hand-code here.
435 litLitToStix :: String -> StixTree
438 "stdout" -> stixFor_stdout
439 "stderr" -> stixFor_stderr
440 "stdin" -> stixFor_stdin
441 other -> error ("\nlitLitToStix: can't handle `" ++ nm ++ "'\n"
442 ++ "suggested workaround: use flag -fvia-C\n")
445 Sizes of the CharLike and IntLike closures that are arranged as arrays
446 in the data segment. (These are in bytes.)
449 -- The INTLIKE base pointer
451 intLikePtr :: StixTree
453 intLikePtr = StInd PtrRep (sStLitLbl SLIT("INTLIKE_closure"))
459 charLike = sStLitLbl SLIT("CHARLIKE_closure")
461 -- Trees for the ErrorIOPrimOp
463 topClosure, errorIO :: StixTree
465 topClosure = StInd PtrRep (sStLitLbl SLIT("TopClosure"))
466 errorIO = StJump (StInd PtrRep (sStLitLbl SLIT("ErrorIO_innards")))
468 mutArrPtrsFrozen_info = sStLitLbl SLIT("MUT_ARR_PTRS_FROZEN_info")
470 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
471 intLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))