08a63568f9714194aa2d0a1def7ff53a2f381177
[ghc-hetmet.git] / ghc / compiler / nativeGen / StixPrim.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1993-1998
3 %
4
5 \begin{code}
6 module StixPrim ( primCode, amodeToStix, amodeToStix' ) where
7
8 #include "HsVersions.h"
9
10 import MachMisc
11 import MachRegs
12 import Stix
13 import StixInteger
14
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 )
25 import Outputable
26
27 import Char             ( ord )
28 \end{code}
29
30 The main honcho here is primCode, which handles the guts of COpStmts.
31
32 \begin{code}
33 primCode
34     :: [CAddrMode]      -- results
35     -> PrimOp           -- op
36     -> [CAddrMode]      -- args
37     -> UniqSM StixTreeList
38 \end{code}
39
40 First, the dreaded @ccall@.  We can't handle @casm@s.
41
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.
44
45 btw Why not let programmer use casm to provide assembly code instead
46 of C code?  ADR
47
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.
52
53 \begin{code}
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)
58
59 primCode [res] IntegerCmpOp args@[sa1,da1, sa2,da2]
60   = gmpCompare res (sa1,da1, sa2,da2)
61
62 primCode [res] IntegerCmpIntOp args@[sa1,da1,ai]
63   = gmpCompareInt res (sa1,da1,ai)
64
65 primCode [res] Integer2IntOp arg@[sa,da]
66   = gmpInteger2Int res (sa,da)
67
68 primCode [res] Integer2WordOp arg@[sa,da]
69   = gmpInteger2Word res (sa,da)
70
71 primCode [res] Int2AddrOp [arg]
72   = simpleCoercion AddrRep res arg
73
74 primCode [res] Addr2IntOp [arg]
75   = simpleCoercion IntRep res arg
76
77 primCode [res] Int2WordOp [arg]
78   = simpleCoercion IntRep{-WordRep?-} res arg
79
80 primCode [res] Word2IntOp [arg]
81   = simpleCoercion IntRep res arg
82 \end{code}
83
84 \begin{code}
85 primCode [res] SameMutableArrayOp args
86   = let
87         compare = StPrim AddrEqOp (map amodeToStix args)
88         assign = StAssign IntRep (amodeToStix res) compare
89     in
90     returnUs (\xs -> assign : xs)
91
92 primCode res@[_] SameMutableByteArrayOp args
93   = primCode res SameMutableArrayOp args
94
95 primCode res@[_] SameMutVarOp args
96   = primCode res SameMutableArrayOp args
97
98 primCode res@[_] SameMVarOp args
99   = primCode res SameMutableArrayOp args
100 \end{code}
101
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).
105
106 \begin{code}
107
108 primCode [lhs] UnsafeFreezeArrayOp [rhs]
109   = let
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
115     in
116     returnUs (\xs -> assign : freeze : xs)
117
118 primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
119   = simpleCoercion PtrRep lhs rhs
120 \end{code}
121
122 Returning the size of (mutable) byte arrays is just
123 an indexing operation.
124
125 \begin{code}
126 primCode [lhs] SizeofByteArrayOp [rhs]
127   = let
128         lhs' = amodeToStix lhs
129         rhs' = amodeToStix rhs
130         sz   = StIndex IntRep rhs' fixedHS
131         assign = StAssign IntRep lhs' (StInd IntRep sz)
132     in
133     returnUs (\xs -> assign : xs)
134
135 primCode [lhs] SizeofMutableByteArrayOp [rhs]
136   = let
137         lhs' = amodeToStix lhs
138         rhs' = amodeToStix rhs
139         sz   = StIndex IntRep rhs' fixedHS
140         assign = StAssign IntRep lhs' (StInd IntRep sz)
141     in
142     returnUs (\xs -> assign : xs)
143
144 \end{code}
145
146 Most other array primitives translate to simple indexing.
147
148 \begin{code}
149 primCode lhs@[_] IndexArrayOp args
150   = primCode lhs ReadArrayOp args
151
152 primCode [lhs] ReadArrayOp [obj, ix]
153   = let
154         lhs' = amodeToStix lhs
155         obj' = amodeToStix obj
156         ix' = amodeToStix ix
157         base = StIndex IntRep obj' arrPtrsHS
158         assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
159     in
160     returnUs (\xs -> assign : xs)
161
162 primCode [] WriteArrayOp [obj, ix, v]
163   = let
164         obj' = amodeToStix obj
165         ix' = amodeToStix ix
166         v' = amodeToStix v
167         base = StIndex IntRep obj' arrPtrsHS
168         assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
169     in
170     returnUs (\xs -> assign : xs)
171
172 primCode lhs@[_] (IndexByteArrayOp pk) args
173   = primCode lhs (ReadByteArrayOp pk) args
174
175 -- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
176
177 primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
178   = let
179         lhs' = amodeToStix lhs
180         obj' = amodeToStix obj
181         ix' = amodeToStix ix
182         base = StIndex IntRep obj' arrWordsHS
183         assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
184     in
185     returnUs (\xs -> assign : xs)
186
187 primCode lhs@[_] (ReadOffAddrOp pk) args
188   = primCode lhs (IndexOffAddrOp pk) args
189
190 primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
191   = let
192         lhs' = amodeToStix lhs
193         obj' = amodeToStix obj
194         ix' = amodeToStix ix
195         assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
196     in
197     returnUs (\xs -> assign : xs)
198
199 primCode [lhs] (IndexOffForeignObjOp pk) [obj, ix]
200   = let
201         lhs' = amodeToStix lhs
202         obj' = amodeToStix obj
203         ix' = amodeToStix ix
204         obj'' = StIndex AddrRep obj' fixedHS
205         assign = StAssign pk lhs' (StInd pk (StIndex pk obj'' ix'))
206     in
207     returnUs (\xs -> assign : xs)
208
209 primCode [] (WriteOffAddrOp pk) [obj, ix, v]
210   = let
211         obj' = amodeToStix obj
212         ix' = amodeToStix ix
213         v' = amodeToStix v
214         assign = StAssign pk (StInd pk (StIndex pk obj' ix')) v'
215     in
216     returnUs (\xs -> assign : xs)
217
218 primCode [] (WriteByteArrayOp pk) [obj, ix, v]
219   = let
220         obj' = amodeToStix obj
221         ix' = amodeToStix ix
222         v' = amodeToStix v
223         base = StIndex IntRep obj' arrWordsHS
224         assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
225     in
226     returnUs (\xs -> assign : xs)
227
228 primCode [] WriteForeignObjOp [obj, v]
229   = let
230         obj' = amodeToStix obj
231         v' = amodeToStix v
232         obj'' = StIndex AddrRep obj' (StInt 4711) -- fixedHS
233         assign = StAssign AddrRep (StInd AddrRep obj'') v'
234     in
235     returnUs (\xs -> assign : xs)
236 \end{code}
237
238 \begin{code}
239 --primCode lhs (CCallOp fn is_asm may_gc) rhs
240 primCode lhs (CCallOp (CCall (StaticTarget fn) is_asm may_gc cconv)) rhs
241   | is_asm = error "ERROR: Native code generator can't handle casm"
242   | may_gc = error "ERROR: Native code generator can't handle _ccall_GC_\n"
243   | otherwise
244   = case lhs of
245       [] -> returnUs (\xs -> (StCall fn cconv VoidRep args) : xs)
246       [lhs] ->
247           let lhs' = amodeToStix lhs
248               pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
249               call = StAssign pk lhs' (StCall fn cconv pk args)
250           in
251               returnUs (\xs -> call : xs)
252   where
253     args = map amodeCodeForCCall rhs
254     amodeCodeForCCall x =
255         let base = amodeToStix' x
256         in
257             case getAmodeRep x of
258               ArrayRep      -> StIndex PtrRep base arrPtrsHS
259               ByteArrayRep  -> StIndex IntRep base arrWordsHS
260               ForeignObjRep -> StIndex PtrRep base fixedHS
261               _ -> base
262 \end{code}
263
264 DataToTagOp won't work for 64-bit archs, as it is.
265
266 \begin{code}
267 primCode [lhs] DataToTagOp [arg]
268   = let lhs'        = amodeToStix lhs
269         arg'        = amodeToStix arg
270         infoptr     = StInd PtrRep arg'
271         word_32     = StInd WordRep (StIndex PtrRep infoptr (StInt (-1)))
272         masked_le32 = StPrim SrlOp [word_32, StInt 16]
273         masked_be32 = StPrim AndOp [word_32, StInt 65535]
274 #ifdef WORDS_BIGENDIAN
275         masked      = masked_be32
276 #else
277         masked      = masked_le32
278 #endif
279         assign      = StAssign IntRep lhs' masked
280     in
281     returnUs (\xs -> assign : xs)
282 \end{code}
283
284 MutVars are pretty simple.
285 #define writeMutVarzh(a,v)       (P_)(((StgMutVar *)(a))->var)=(v)
286
287 \begin{code}
288 primCode [] WriteMutVarOp [aa,vv]
289    = let aa_s      = amodeToStix aa
290          vv_s      = amodeToStix vv
291          var_field = StIndex PtrRep aa_s fixedHS
292          assign    = StAssign PtrRep (StInd PtrRep var_field) vv_s
293      in
294      returnUs (\xs -> assign : xs)
295
296 primCode [rr] ReadMutVarOp [aa]
297    = let aa_s      = amodeToStix aa
298          rr_s      = amodeToStix rr
299          var_field = StIndex PtrRep aa_s fixedHS
300          assign    = StAssign PtrRep rr_s (StInd PtrRep var_field)
301      in
302      returnUs (\xs -> assign : xs)
303 \end{code}
304
305 Now the more mundane operations.
306
307 \begin{code}
308 primCode lhs op rhs
309   = let
310         lhs' = map amodeToStix  lhs
311         rhs' = map amodeToStix' rhs
312         pk   = getAmodeRep (head lhs)
313     in
314     returnUs (\ xs -> simplePrim pk lhs' op rhs' : xs)
315 \end{code}
316
317 \begin{code}
318 simpleCoercion
319       :: PrimRep
320       -> CAddrMode
321       -> CAddrMode
322       -> UniqSM StixTreeList
323
324 simpleCoercion pk lhs rhs
325   = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
326 \end{code}
327
328 Here we try to rewrite primitives into a form the code generator can
329 understand.  Any primitives not handled here must be handled at the
330 level of the specific code generator.
331
332 \begin{code}
333 simplePrim
334     :: PrimRep          -- Rep of first destination
335     -> [StixTree]       -- Destinations
336     -> PrimOp
337     -> [StixTree]
338     -> StixTree
339 \end{code}
340
341 Now look for something more conventional.
342
343 \begin{code}
344 simplePrim pk [lhs] op rest  = StAssign pk lhs (StPrim op rest)
345 simplePrim pk as    op bs    = simplePrim_error op
346
347 simplePrim_error op
348     = 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")
349 \end{code}
350
351 %---------------------------------------------------------------------
352
353 Here we generate the Stix code for CAddrModes.
354
355 When a character is fetched from a mixed type location, we have to do
356 an extra cast.  This is reflected in amodeCode', which is for rhs
357 amodes that might possibly need the extra cast.
358
359 \begin{code}
360 amodeToStix, amodeToStix' :: CAddrMode -> StixTree
361
362 amodeToStix'{-'-} am@(CVal rr CharRep)
363     | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
364     | otherwise = amodeToStix am
365
366 amodeToStix' am = amodeToStix am
367
368 -----------
369 amodeToStix am@(CVal rr CharRep)
370   | mixedTypeLocn am
371   = StInd IntRep (amodeToStix (CAddr rr))
372
373 amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
374
375 amodeToStix (CAddr (SpRel off))
376   = StIndex PtrRep stgSp (StInt (toInteger IBOX(off)))
377
378 amodeToStix (CAddr (HpRel off))
379   = StIndex IntRep stgHp (StInt (toInteger (- IBOX(off))))
380
381 amodeToStix (CAddr (NodeRel off))
382   = StIndex IntRep stgNode (StInt (toInteger IBOX(off)))
383
384 amodeToStix (CAddr (CIndex base off pk))
385   = StIndex pk (amodeToStix base) (amodeToStix off)
386
387 amodeToStix (CReg magic)    = StReg (StixMagicId magic)
388 amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
389
390 amodeToStix (CLbl      lbl _) = StCLbl lbl
391
392  -- For CharLike and IntLike, we attempt some trivial constant-folding here.
393
394 amodeToStix (CCharLike (CLit (MachChar c)))
395   = StLitLbl ((<>) (ptext SLIT("CHARLIKE_closure+")) (int off))
396   where
397     off = charLikeSize * ord c
398
399 amodeToStix (CCharLike x)
400   = StIndex CharRep charLike off
401   where
402     off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
403
404 amodeToStix (CIntLike (CLit (MachInt i)))
405   = StLitLbl ((<>) (ptext SLIT("INTLIKE_closure+")) (int off))
406   where
407     off = intLikeSize * (fromInteger (i - mIN_INTLIKE))
408
409 amodeToStix (CIntLike x)
410   = panic "CIntLike"
411
412 amodeToStix (CLit core)
413   = case core of
414       MachChar c     -> StInt (toInteger (ord c))
415       MachStr s      -> StString s
416       MachAddr a     -> StInt a
417       MachInt i      -> StInt i
418       MachWord w     -> case word2IntLit core of MachInt iw -> StInt iw
419       MachLitLit s _ -> litLitToStix (_UNPK_ s)
420       MachFloat d    -> StDouble d
421       MachDouble d   -> StDouble d
422       _ -> panic "amodeToStix:core literal"
423
424 amodeToStix (CLitLit s _)
425    = litLitToStix (_UNPK_ s)
426
427 amodeToStix (CMacroExpr _ macro [arg])
428   = case macro of
429       ENTRY_CODE -> amodeToStix arg
430       ARG_TAG    -> amodeToStix arg -- just an integer no. of words
431       GET_TAG    -> 
432 #ifdef WORDS_BIGENDIAN
433                     StPrim AndOp 
434                         [StInd WordRep (StIndex PtrRep (amodeToStix arg)
435                                                 (StInt (toInteger (-1)))),
436                          StInt 65535]
437 #else
438                     StPrim SrlOp 
439                         [StInd WordRep (StIndex PtrRep (amodeToStix arg)
440                                                 (StInt (toInteger (-1)))),
441                          StInt 16]
442 #endif
443       UPD_FRAME_UPDATEE
444          -> StInd PtrRep (StIndex PtrRep (amodeToStix arg) 
445                                          (StInt (toInteger uF_UPDATEE)))
446 -- XXX!!!
447 -- GET_TAG(info_ptr) is supposed to be  get_itbl(info_ptr)->srt_len,
448 -- which we've had to hand-code here.
449
450 litLitToStix :: String -> StixTree
451 litLitToStix nm
452    = case nm of
453         "stdout" -> stixFor_stdout
454         "stderr" -> stixFor_stderr
455         "stdin"  -> stixFor_stdin
456         other    -> error ("\nlitLitToStix: can't handle `" ++ nm ++ "'\n" 
457                            ++ "suggested workaround: use flag -fvia-C\n")
458 \end{code}
459
460 Sizes of the CharLike and IntLike closures that are arranged as arrays
461 in the data segment.  (These are in bytes.)
462
463 \begin{code}
464 -- The INTLIKE base pointer
465
466 intLikePtr :: StixTree
467
468 intLikePtr = StInd PtrRep (sStLitLbl SLIT("INTLIKE_closure"))
469
470 -- The CHARLIKE base
471
472 charLike :: StixTree
473
474 charLike = sStLitLbl SLIT("CHARLIKE_closure")
475
476 -- Trees for the ErrorIOPrimOp
477
478 topClosure, errorIO :: StixTree
479
480 topClosure = StInd PtrRep (sStLitLbl SLIT("TopClosure"))
481 errorIO = StJump (StInd PtrRep (sStLitLbl SLIT("ErrorIO_innards")))
482
483 mutArrPtrsFrozen_info = sStLitLbl SLIT("MUT_ARR_PTRS_FROZEN_info")
484
485 charLikeSize = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
486 intLikeSize  = (fixedHdrSize + 1) * (fromInteger (sizeOf PtrRep))
487 \end{code}