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 Const ( Literal(..) )
20 import CallConv ( cCallConv )
21 import PrimOp ( PrimOp(..) )
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] (IndexOffAddrOp pk) [obj, ix]
183 lhs' = amodeToStix lhs
184 obj' = amodeToStix obj
186 assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
188 returnUs (\xs -> assign : xs)
190 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
192 lhs' = amodeToStix lhs
193 obj' = amodeToStix obj
195 obj'' = StIndex PtrRep obj' fixedHS
196 assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
198 returnUs (\xs -> assign : xs)
200 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
202 obj' = amodeToStix obj
205 base = StIndex IntRep obj' arrWordsHS
206 assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
208 returnUs (\xs -> assign : xs)
212 --primCode lhs (CCallOp fn is_asm may_gc) rhs
213 primCode lhs (CCallOp (Left fn) is_asm may_gc cconv) rhs
214 | is_asm = error "ERROR: Native code generator can't handle casm"
215 | may_gc = error "ERROR: Native code generator can't handle _ccall_GC_\n"
218 [] -> returnUs (\xs -> (StCall fn cconv VoidRep args) : xs)
220 let lhs' = amodeToStix lhs
221 pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
222 call = StAssign pk lhs' (StCall fn cconv pk args)
224 returnUs (\xs -> call : xs)
226 args = map amodeCodeForCCall rhs
227 amodeCodeForCCall x =
228 let base = amodeToStix' x
230 case getAmodeRep x of
231 ArrayRep -> StIndex PtrRep base arrPtrsHS
232 ByteArrayRep -> StIndex IntRep base arrWordsHS
233 ForeignObjRep -> StIndex PtrRep base fixedHS
237 DataToTagOp won't work for 64-bit archs, as it is.
240 primCode [lhs] DataToTagOp [arg]
241 = let lhs' = amodeToStix lhs
242 arg' = amodeToStix arg
243 infoptr = StInd PtrRep arg'
244 word_32 = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
245 masked_le32 = StPrim SrlOp [word_32, StInt 16]
246 masked_be32 = StPrim AndOp [word_32, StInt 65535]
247 #ifdef WORDS_BIGENDIAN
252 assign = StAssign IntRep lhs' masked
254 returnUs (\xs -> assign : xs)
257 MutVars are pretty simple.
258 #define writeMutVarzh(a,v) (P_)(((StgMutVar *)(a))->var)=(v)
261 primCode [] WriteMutVarOp [aa,vv]
262 = let aa_s = amodeToStix aa
263 vv_s = amodeToStix vv
264 var_field = StIndex PtrRep aa_s fixedHS
265 assign = StAssign PtrRep (StInd PtrRep var_field) vv_s
267 returnUs (\xs -> assign : xs)
269 primCode [rr] ReadMutVarOp [aa]
270 = let aa_s = amodeToStix aa
271 rr_s = amodeToStix rr
272 var_field = StIndex PtrRep aa_s fixedHS
273 assign = StAssign PtrRep rr_s (StInd PtrRep var_field)
275 returnUs (\xs -> assign : xs)
278 Now the more mundane operations.
283 lhs' = map amodeToStix lhs
284 rhs' = map amodeToStix' rhs
285 pk = getAmodeRep (head lhs)
287 returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
295 -> UniqSM StixTreeList
297 simpleCoercion pk lhs rhs
298 = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
301 Here we try to rewrite primitives into a form the code generator can
302 understand. Any primitives not handled here must be handled at the
303 level of the specific code generator.
307 :: PrimRep -- Rep of first destination
308 -> [StixTree] -- Destinations
314 Now look for something more conventional.
317 simplePrim pk [lhs] op rest = StAssign pk lhs (StPrim op rest)
318 simplePrim pk as op bs = simplePrim_error op
321 = 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")
324 %---------------------------------------------------------------------
326 Here we generate the Stix code for CAddrModes.
328 When a character is fetched from a mixed type location, we have to do
329 an extra cast. This is reflected in amodeCode', which is for rhs
330 amodes that might possibly need the extra cast.
333 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
335 amodeToStix'{-'-} am@(CVal rr CharRep)
336 | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
337 | otherwise = amodeToStix am
339 amodeToStix' am = amodeToStix am
342 amodeToStix am@(CVal rr CharRep)
344 = StInd IntRep (amodeToStix (CAddr rr))
346 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
348 amodeToStix (CAddr (SpRel off))
349 = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
351 amodeToStix (CAddr (HpRel off))
352 = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
354 amodeToStix (CAddr (NodeRel off))
355 = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
357 amodeToStix (CAddr (CIndex base off pk))
358 = StIndex pk (amodeToStix base) (amodeToStix off)
360 amodeToStix (CReg magic) = StReg (StixMagicId magic)
361 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
363 amodeToStix (CLbl lbl _) = StCLbl lbl
365 -- For CharLike and IntLike, we attempt some trivial constant-folding here.
367 amodeToStix (CCharLike (CLit (MachChar c)))
368 = StLitLbl ((<>) (ptext SLIT("CHARLIKE_closure+")) (int off))
370 off = charLikeSize * ord c
372 amodeToStix (CCharLike x)
373 = StIndex CharRep charLike off
375 off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
377 amodeToStix (CIntLike (CLit (MachInt i _)))
378 = StLitLbl ((<>) (ptext SLIT("INTLIKE_closure+")) (int off))
380 off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
382 amodeToStix (CIntLike x)
385 amodeToStix (CLit core)
387 MachChar c -> StInt (toInteger (ord c))
388 MachStr s -> StString s
389 MachAddr a -> StInt a
390 MachInt i _ -> StInt (toInteger i)
391 MachLitLit s _ -> {-trace (_UNPK_ s ++ "\n")-} (litLitToStix (_UNPK_ s))
392 MachFloat d -> StDouble d
393 MachDouble d -> StDouble d
394 _ -> panic "amodeToStix:core literal"
396 amodeToStix (CLitLit s _)
397 = litLitToStix (_UNPK_ s)
399 amodeToStix (CMacroExpr _ macro [arg])
401 ENTRY_CODE -> amodeToStix arg
402 ARG_TAG -> amodeToStix arg -- just an integer no. of words
404 #ifdef WORDS_BIGENDIAN
406 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
407 (StInt (toInteger (-1)))),
411 [StInd WordRep (StIndex PtrRep (amodeToStix arg)
412 (StInt (toInteger (-1)))),
416 -> StInd PtrRep (StIndex PtrRep (amodeToStix arg)
417 (StInt (toInteger uF_UPDATEE)))
419 -- GET_TAG(info_ptr) is supposed to be get_itbl(info_ptr)->srt_len,
420 -- which we've had to hand-code here.
422 litLitToStix :: String -> StixTree
425 "stdout" -> stixFor_stdout
426 "stderr" -> stixFor_stderr
427 "stdin" -> stixFor_stdin
428 other -> error ("\nlitLitToStix: can't handle `" ++ nm ++ "'\n"
429 ++ "suggested workaround: use flag -fvia-C\n")
432 Sizes of the CharLike and IntLike closures that are arranged as arrays
433 in the data segment. (These are in bytes.)
436 -- The INTLIKE base pointer
438 intLikePtr :: StixTree
440 intLikePtr = StInd PtrRep (sStLitLbl SLIT("INTLIKE_closure"))
446 charLike = sStLitLbl SLIT("CHARLIKE_closure")
448 -- Trees for the ErrorIOPrimOp
450 topClosure, errorIO :: StixTree
452 topClosure = StInd PtrRep (sStLitLbl SLIT("TopClosure"))
453 errorIO = StJump (StInd PtrRep (sStLitLbl SLIT("ErrorIO_innards")))
455 mutArrPtrsFrozen_info = sStLitLbl SLIT("MUT_ARR_PTRS_FROZEN_info")
457 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
458 intLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))