[project @ 2005-07-21 10:46:12 by simonmar]
[ghc-hetmet.git] / ghc / compiler / nativeGen / MachCodeGen.hs
1 -----------------------------------------------------------------------------
2 --
3 -- Generating machine code (instruction selection)
4 --
5 -- (c) The University of Glasgow 1996-2004
6 --
7 -----------------------------------------------------------------------------
8
9 -- This is a big module, but, if you pay attention to
10 -- (a) the sectioning, (b) the type signatures, and
11 -- (c) the #if blah_TARGET_ARCH} things, the
12 -- structure should not be too overwhelming.
13
14 module MachCodeGen ( cmmTopCodeGen, InstrBlock ) where
15
16 #include "HsVersions.h"
17 #include "nativeGen/NCG.h"
18 #include "MachDeps.h"
19
20 -- NCG stuff:
21 import MachInstrs
22 import MachRegs
23 import NCGMonad
24 import PositionIndependentCode ( cmmMakeDynamicReference, initializePicBase )
25
26 -- Our intermediate code:
27 import PprCmm           ( pprExpr )
28 import Cmm
29 import MachOp
30 import CLabel
31
32 -- The rest:
33 import StaticFlags      ( opt_PIC )
34 import ForeignCall      ( CCallConv(..) )
35 import OrdList
36 import Pretty
37 import Outputable
38 import FastString
39 import FastTypes        ( isFastTrue )
40 import Constants        ( wORD_SIZE )
41
42 #ifdef DEBUG
43 import Outputable       ( assertPanic )
44 import TRACE            ( trace )
45 #endif
46
47 import Control.Monad    ( mapAndUnzipM )
48 import Maybe            ( fromJust )
49 import DATA_BITS
50 import DATA_WORD
51
52 -- -----------------------------------------------------------------------------
53 -- Top-level of the instruction selector
54
55 -- | 'InstrBlock's are the insn sequences generated by the insn selectors.
56 -- They are really trees of insns to facilitate fast appending, where a
57 -- left-to-right traversal (pre-order?) yields the insns in the correct
58 -- order.
59
60 type InstrBlock = OrdList Instr
61
62 cmmTopCodeGen :: CmmTop -> NatM [NatCmmTop]
63 cmmTopCodeGen (CmmProc info lab params blocks) = do
64   (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
65   picBaseMb <- getPicBaseMaybeNat
66   let proc = CmmProc info lab params (concat nat_blocks)
67       tops = proc : concat statics
68   case picBaseMb of
69       Just picBase -> initializePicBase picBase tops
70       Nothing -> return tops
71   
72 cmmTopCodeGen (CmmData sec dat) = do
73   return [CmmData sec dat]  -- no translation, we just use CmmStatic
74
75 basicBlockCodeGen :: CmmBasicBlock -> NatM ([NatBasicBlock],[NatCmmTop])
76 basicBlockCodeGen (BasicBlock id stmts) = do
77   instrs <- stmtsToInstrs stmts
78   -- code generation may introduce new basic block boundaries, which
79   -- are indicated by the NEWBLOCK instruction.  We must split up the
80   -- instruction stream into basic blocks again.  Also, we extract
81   -- LDATAs here too.
82   let
83         (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs
84         
85         mkBlocks (NEWBLOCK id) (instrs,blocks,statics) 
86           = ([], BasicBlock id instrs : blocks, statics)
87         mkBlocks (LDATA sec dat) (instrs,blocks,statics) 
88           = (instrs, blocks, CmmData sec dat:statics)
89         mkBlocks instr (instrs,blocks,statics)
90           = (instr:instrs, blocks, statics)
91   -- in
92   return (BasicBlock id top : other_blocks, statics)
93
94 stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
95 stmtsToInstrs stmts
96    = do instrss <- mapM stmtToInstrs stmts
97         return (concatOL instrss)
98
99 stmtToInstrs :: CmmStmt -> NatM InstrBlock
100 stmtToInstrs stmt = case stmt of
101     CmmNop         -> return nilOL
102     CmmComment s   -> return (unitOL (COMMENT s))
103
104     CmmAssign reg src
105       | isFloatingRep kind -> assignReg_FltCode kind reg src
106 #if WORD_SIZE_IN_BITS==32
107       | kind == I64        -> assignReg_I64Code      reg src
108 #endif
109       | otherwise          -> assignReg_IntCode kind reg src
110         where kind = cmmRegRep reg
111
112     CmmStore addr src
113       | isFloatingRep kind -> assignMem_FltCode kind addr src
114 #if WORD_SIZE_IN_BITS==32
115       | kind == I64      -> assignMem_I64Code      addr src
116 #endif
117       | otherwise        -> assignMem_IntCode kind addr src
118         where kind = cmmExprRep src
119
120     CmmCall target result_regs args vols
121        -> genCCall target result_regs args vols
122
123     CmmBranch id          -> genBranch id
124     CmmCondBranch arg id  -> genCondJump id arg
125     CmmSwitch arg ids     -> genSwitch arg ids
126     CmmJump arg params    -> genJump arg
127
128 -- -----------------------------------------------------------------------------
129 -- General things for putting together code sequences
130
131 -- Expand CmmRegOff.  ToDo: should we do it this way around, or convert
132 -- CmmExprs into CmmRegOff?
133 mangleIndexTree :: CmmExpr -> CmmExpr
134 mangleIndexTree (CmmRegOff reg off)
135   = CmmMachOp (MO_Add rep) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) rep)]
136   where rep = cmmRegRep reg
137
138 -- -----------------------------------------------------------------------------
139 --  Code gen for 64-bit arithmetic on 32-bit platforms
140
141 {-
142 Simple support for generating 64-bit code (ie, 64 bit values and 64
143 bit assignments) on 32-bit platforms.  Unlike the main code generator
144 we merely shoot for generating working code as simply as possible, and
145 pay little attention to code quality.  Specifically, there is no
146 attempt to deal cleverly with the fixed-vs-floating register
147 distinction; all values are generated into (pairs of) floating
148 registers, even if this would mean some redundant reg-reg moves as a
149 result.  Only one of the VRegUniques is returned, since it will be
150 of the VRegUniqueLo form, and the upper-half VReg can be determined
151 by applying getHiVRegFromLo to it.
152 -}
153
154 data ChildCode64        -- a.k.a "Register64"
155    = ChildCode64 
156         InstrBlock      -- code
157         Reg             -- the lower 32-bit temporary which contains the
158                         -- result; use getHiVRegFromLo to find the other
159                         -- VRegUnique.  Rules of this simplified insn
160                         -- selection game are therefore that the returned
161                         -- Reg may be modified
162
163 #if WORD_SIZE_IN_BITS==32
164 assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock
165 assignReg_I64Code :: CmmReg  -> CmmExpr -> NatM InstrBlock
166 #endif
167
168 #ifndef x86_64_TARGET_ARCH
169 iselExpr64        :: CmmExpr -> NatM ChildCode64
170 #endif
171
172 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
173
174 #if i386_TARGET_ARCH
175
176 assignMem_I64Code addrTree valueTree = do
177   Amode addr addr_code <- getAmode addrTree
178   ChildCode64 vcode rlo <- iselExpr64 valueTree
179   let 
180         rhi = getHiVRegFromLo rlo
181
182         -- Little-endian store
183         mov_lo = MOV I32 (OpReg rlo) (OpAddr addr)
184         mov_hi = MOV I32 (OpReg rhi) (OpAddr (fromJust (addrOffset addr 4)))
185   -- in
186   return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
187
188
189 assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
190    ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
191    let 
192          r_dst_lo = mkVReg u_dst I32
193          r_dst_hi = getHiVRegFromLo r_dst_lo
194          r_src_hi = getHiVRegFromLo r_src_lo
195          mov_lo = MOV I32 (OpReg r_src_lo) (OpReg r_dst_lo)
196          mov_hi = MOV I32 (OpReg r_src_hi) (OpReg r_dst_hi)
197    -- in
198    return (
199         vcode `snocOL` mov_lo `snocOL` mov_hi
200      )
201
202 assignReg_I64Code lvalue valueTree
203    = panic "assignReg_I64Code(i386): invalid lvalue"
204
205 ------------
206
207 iselExpr64 (CmmLit (CmmInt i _)) = do
208   (rlo,rhi) <- getNewRegPairNat I32
209   let
210         r = fromIntegral (fromIntegral i :: Word32)
211         q = fromIntegral ((fromIntegral i `shiftR` 32) :: Word32)
212         code = toOL [
213                 MOV I32 (OpImm (ImmInteger r)) (OpReg rlo),
214                 MOV I32 (OpImm (ImmInteger q)) (OpReg rhi)
215                 ]
216   -- in
217   return (ChildCode64 code rlo)
218
219 iselExpr64 (CmmLoad addrTree I64) = do
220    Amode addr addr_code <- getAmode addrTree
221    (rlo,rhi) <- getNewRegPairNat I32
222    let 
223         mov_lo = MOV I32 (OpAddr addr) (OpReg rlo)
224         mov_hi = MOV I32 (OpAddr (fromJust (addrOffset addr 4))) (OpReg rhi)
225    -- in
226    return (
227             ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi) 
228                         rlo
229      )
230
231 iselExpr64 (CmmReg (CmmLocal (LocalReg vu I64)))
232    = return (ChildCode64 nilOL (mkVReg vu I32))
233          
234 -- we handle addition, but rather badly
235 iselExpr64 (CmmMachOp (MO_Add _) [e1, CmmLit (CmmInt i _)]) = do
236    ChildCode64 code1 r1lo <- iselExpr64 e1
237    (rlo,rhi) <- getNewRegPairNat I32
238    let
239         r = fromIntegral (fromIntegral i :: Word32)
240         q = fromIntegral ((fromIntegral i `shiftR` 32) :: Word32)
241         r1hi = getHiVRegFromLo r1lo
242         code =  code1 `appOL`
243                 toOL [ MOV I32 (OpReg r1lo) (OpReg rlo),
244                        ADD I32 (OpImm (ImmInteger r)) (OpReg rlo),
245                        MOV I32 (OpReg r1hi) (OpReg rhi),
246                        ADC I32 (OpImm (ImmInteger q)) (OpReg rhi) ]
247    -- in
248    return (ChildCode64 code rlo)
249
250 iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
251    ChildCode64 code1 r1lo <- iselExpr64 e1
252    ChildCode64 code2 r2lo <- iselExpr64 e2
253    (rlo,rhi) <- getNewRegPairNat I32
254    let
255         r1hi = getHiVRegFromLo r1lo
256         r2hi = getHiVRegFromLo r2lo
257         code =  code1 `appOL`
258                 code2 `appOL`
259                 toOL [ MOV I32 (OpReg r1lo) (OpReg rlo),
260                        ADD I32 (OpReg r2lo) (OpReg rlo),
261                        MOV I32 (OpReg r1hi) (OpReg rhi),
262                        ADC I32 (OpReg r2hi) (OpReg rhi) ]
263    -- in
264    return (ChildCode64 code rlo)
265
266 iselExpr64 expr
267    = pprPanic "iselExpr64(i386)" (ppr expr)
268
269 #endif /* i386_TARGET_ARCH */
270
271 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
272
273 #if sparc_TARGET_ARCH
274
275 assignMem_I64Code addrTree valueTree = do
276      Amode addr addr_code <- getAmode addrTree
277      ChildCode64 vcode rlo <- iselExpr64 valueTree  
278      (src, code) <- getSomeReg addrTree
279      let 
280          rhi = getHiVRegFromLo rlo
281          -- Big-endian store
282          mov_hi = ST I32 rhi (AddrRegImm src (ImmInt 0))
283          mov_lo = ST I32 rlo (AddrRegImm src (ImmInt 4))
284      return (vcode `appOL` code `snocOL` mov_hi `snocOL` mov_lo)
285
286 assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
287      ChildCode64 vcode r_src_lo <- iselExpr64 valueTree    
288      let 
289          r_dst_lo = mkVReg u_dst pk
290          r_dst_hi = getHiVRegFromLo r_dst_lo
291          r_src_hi = getHiVRegFromLo r_src_lo
292          mov_lo = mkMOV r_src_lo r_dst_lo
293          mov_hi = mkMOV r_src_hi r_dst_hi
294          mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
295      return (vcode `snocOL` mov_hi `snocOL` mov_lo)
296 assignReg_I64Code lvalue valueTree
297    = panic "assignReg_I64Code(sparc): invalid lvalue"
298
299
300 -- Don't delete this -- it's very handy for debugging.
301 --iselExpr64 expr 
302 --   | trace ("iselExpr64: " ++ showSDoc (ppr expr)) False
303 --   = panic "iselExpr64(???)"
304
305 iselExpr64 (CmmLoad addrTree I64) = do
306      Amode (AddrRegReg r1 r2) addr_code <- getAmode addrTree
307      rlo <- getNewRegNat I32
308      let rhi = getHiVRegFromLo rlo
309          mov_hi = LD I32 (AddrRegImm r1 (ImmInt 0)) rhi
310          mov_lo = LD I32 (AddrRegImm r1 (ImmInt 4)) rlo
311      return (
312             ChildCode64 (addr_code `snocOL` mov_hi `snocOL` mov_lo) 
313                          rlo
314           )
315
316 iselExpr64 (CmmReg (CmmLocal (LocalReg uq I64))) = do
317      r_dst_lo <-  getNewRegNat I32
318      let r_dst_hi = getHiVRegFromLo r_dst_lo
319          r_src_lo = mkVReg uq I32
320          r_src_hi = getHiVRegFromLo r_src_lo
321          mov_lo = mkMOV r_src_lo r_dst_lo
322          mov_hi = mkMOV r_src_hi r_dst_hi
323          mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg
324      return (
325             ChildCode64 (toOL [mov_hi, mov_lo]) r_dst_lo
326          )
327
328 iselExpr64 expr
329    = pprPanic "iselExpr64(sparc)" (ppr expr)
330
331 #endif /* sparc_TARGET_ARCH */
332
333 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
334
335 #if powerpc_TARGET_ARCH
336
337 getI64Amodes :: CmmExpr -> NatM (AddrMode, AddrMode, InstrBlock)
338 getI64Amodes addrTree = do
339     Amode hi_addr addr_code <- getAmode addrTree
340     case addrOffset hi_addr 4 of
341         Just lo_addr -> return (hi_addr, lo_addr, addr_code)
342         Nothing      -> do (hi_ptr, code) <- getSomeReg addrTree
343                            return (AddrRegImm hi_ptr (ImmInt 0),
344                                    AddrRegImm hi_ptr (ImmInt 4),
345                                    code)
346
347 assignMem_I64Code addrTree valueTree = do
348         (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
349         ChildCode64 vcode rlo <- iselExpr64 valueTree
350         let 
351                 rhi = getHiVRegFromLo rlo
352
353                 -- Big-endian store
354                 mov_hi = ST I32 rhi hi_addr
355                 mov_lo = ST I32 rlo lo_addr
356         -- in
357         return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)
358
359 assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree = do
360    ChildCode64 vcode r_src_lo <- iselExpr64 valueTree
361    let 
362          r_dst_lo = mkVReg u_dst I32
363          r_dst_hi = getHiVRegFromLo r_dst_lo
364          r_src_hi = getHiVRegFromLo r_src_lo
365          mov_lo = MR r_dst_lo r_src_lo
366          mov_hi = MR r_dst_hi r_src_hi
367    -- in
368    return (
369         vcode `snocOL` mov_lo `snocOL` mov_hi
370      )
371
372 assignReg_I64Code lvalue valueTree
373    = panic "assignReg_I64Code(powerpc): invalid lvalue"
374
375
376 -- Don't delete this -- it's very handy for debugging.
377 --iselExpr64 expr 
378 --   | trace ("iselExpr64: " ++ showSDoc (pprCmmExpr expr)) False
379 --   = panic "iselExpr64(???)"
380
381 iselExpr64 (CmmLoad addrTree I64) = do
382     (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree
383     (rlo, rhi) <- getNewRegPairNat I32
384     let mov_hi = LD I32 rhi hi_addr
385         mov_lo = LD I32 rlo lo_addr
386     return $ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi) 
387                          rlo
388
389 iselExpr64 (CmmReg (CmmLocal (LocalReg vu I64)))
390    = return (ChildCode64 nilOL (mkVReg vu I32))
391
392 iselExpr64 (CmmLit (CmmInt i _)) = do
393   (rlo,rhi) <- getNewRegPairNat I32
394   let
395         half0 = fromIntegral (fromIntegral i :: Word16)
396         half1 = fromIntegral ((fromIntegral i `shiftR` 16) :: Word16)
397         half2 = fromIntegral ((fromIntegral i `shiftR` 32) :: Word16)
398         half3 = fromIntegral ((fromIntegral i `shiftR` 48) :: Word16)
399         
400         code = toOL [
401                 LIS rlo (ImmInt half1),
402                 OR rlo rlo (RIImm $ ImmInt half0),
403                 LIS rhi (ImmInt half3),
404                 OR rlo rlo (RIImm $ ImmInt half2)
405                 ]
406   -- in
407   return (ChildCode64 code rlo)
408
409 iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do
410    ChildCode64 code1 r1lo <- iselExpr64 e1
411    ChildCode64 code2 r2lo <- iselExpr64 e2
412    (rlo,rhi) <- getNewRegPairNat I32
413    let
414         r1hi = getHiVRegFromLo r1lo
415         r2hi = getHiVRegFromLo r2lo
416         code =  code1 `appOL`
417                 code2 `appOL`
418                 toOL [ ADDC rlo r1lo r2lo,
419                        ADDE rhi r1hi r2hi ]
420    -- in
421    return (ChildCode64 code rlo)
422
423 iselExpr64 expr
424    = pprPanic "iselExpr64(powerpc)" (ppr expr)
425
426 #endif /* powerpc_TARGET_ARCH */
427
428
429 -- -----------------------------------------------------------------------------
430 -- The 'Register' type
431
432 -- 'Register's passed up the tree.  If the stix code forces the register
433 -- to live in a pre-decided machine register, it comes out as @Fixed@;
434 -- otherwise, it comes out as @Any@, and the parent can decide which
435 -- register to put it in.
436
437 data Register
438   = Fixed   MachRep Reg InstrBlock
439   | Any     MachRep (Reg -> InstrBlock)
440
441 swizzleRegisterRep :: Register -> MachRep -> Register
442 swizzleRegisterRep (Fixed _ reg code) rep = Fixed rep reg code
443 swizzleRegisterRep (Any _ codefn)     rep = Any rep codefn
444
445
446 -- -----------------------------------------------------------------------------
447 -- Utils based on getRegister, below
448
449 -- The dual to getAnyReg: compute an expression into a register, but
450 -- we don't mind which one it is.
451 getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)
452 getSomeReg expr = do
453   r <- getRegister expr
454   case r of
455     Any rep code -> do
456         tmp <- getNewRegNat rep
457         return (tmp, code tmp)
458     Fixed _ reg code -> 
459         return (reg, code)
460
461 -- -----------------------------------------------------------------------------
462 -- Grab the Reg for a CmmReg
463
464 getRegisterReg :: CmmReg -> Reg
465
466 getRegisterReg (CmmLocal (LocalReg u pk))
467   = mkVReg u pk
468
469 getRegisterReg (CmmGlobal mid)
470   = case get_GlobalReg_reg_or_addr mid of
471        Left (RealReg rrno) -> RealReg rrno
472        _other -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)
473           -- By this stage, the only MagicIds remaining should be the
474           -- ones which map to a real machine register on this
475           -- platform.  Hence ...
476
477
478 -- -----------------------------------------------------------------------------
479 -- Generate code to get a subtree into a Register
480
481 -- Don't delete this -- it's very handy for debugging.
482 --getRegister expr 
483 --   | trace ("getRegister: " ++ showSDoc (pprCmmExpr expr)) False
484 --   = panic "getRegister(???)"
485
486 getRegister :: CmmExpr -> NatM Register
487
488 getRegister (CmmReg (CmmGlobal PicBaseReg))
489   = do
490       reg <- getPicBaseNat wordRep
491       return (Fixed wordRep reg nilOL)
492
493 getRegister (CmmReg reg) 
494   = return (Fixed (cmmRegRep reg) (getRegisterReg reg) nilOL)
495
496 getRegister tree@(CmmRegOff _ _) 
497   = getRegister (mangleIndexTree tree)
498
499 -- end of machine-"independent" bit; here we go on the rest...
500
501 #if alpha_TARGET_ARCH
502
503 getRegister (StDouble d)
504   = getBlockIdNat                   `thenNat` \ lbl ->
505     getNewRegNat PtrRep             `thenNat` \ tmp ->
506     let code dst = mkSeqInstrs [
507             LDATA RoDataSegment lbl [
508                     DATA TF [ImmLab (rational d)]
509                 ],
510             LDA tmp (AddrImm (ImmCLbl lbl)),
511             LD TF dst (AddrReg tmp)]
512     in
513         return (Any F64 code)
514
515 getRegister (StPrim primop [x]) -- unary PrimOps
516   = case primop of
517       IntNegOp -> trivialUCode (NEG Q False) x
518
519       NotOp    -> trivialUCode NOT x
520
521       FloatNegOp  -> trivialUFCode FloatRep  (FNEG TF) x
522       DoubleNegOp -> trivialUFCode F64 (FNEG TF) x
523
524       OrdOp -> coerceIntCode IntRep x
525       ChrOp -> chrCode x
526
527       Float2IntOp  -> coerceFP2Int    x
528       Int2FloatOp  -> coerceInt2FP pr x
529       Double2IntOp -> coerceFP2Int    x
530       Int2DoubleOp -> coerceInt2FP pr x
531
532       Double2FloatOp -> coerceFltCode x
533       Float2DoubleOp -> coerceFltCode x
534
535       other_op -> getRegister (StCall fn CCallConv F64 [x])
536         where
537           fn = case other_op of
538                  FloatExpOp    -> FSLIT("exp")
539                  FloatLogOp    -> FSLIT("log")
540                  FloatSqrtOp   -> FSLIT("sqrt")
541                  FloatSinOp    -> FSLIT("sin")
542                  FloatCosOp    -> FSLIT("cos")
543                  FloatTanOp    -> FSLIT("tan")
544                  FloatAsinOp   -> FSLIT("asin")
545                  FloatAcosOp   -> FSLIT("acos")
546                  FloatAtanOp   -> FSLIT("atan")
547                  FloatSinhOp   -> FSLIT("sinh")
548                  FloatCoshOp   -> FSLIT("cosh")
549                  FloatTanhOp   -> FSLIT("tanh")
550                  DoubleExpOp   -> FSLIT("exp")
551                  DoubleLogOp   -> FSLIT("log")
552                  DoubleSqrtOp  -> FSLIT("sqrt")
553                  DoubleSinOp   -> FSLIT("sin")
554                  DoubleCosOp   -> FSLIT("cos")
555                  DoubleTanOp   -> FSLIT("tan")
556                  DoubleAsinOp  -> FSLIT("asin")
557                  DoubleAcosOp  -> FSLIT("acos")
558                  DoubleAtanOp  -> FSLIT("atan")
559                  DoubleSinhOp  -> FSLIT("sinh")
560                  DoubleCoshOp  -> FSLIT("cosh")
561                  DoubleTanhOp  -> FSLIT("tanh")
562   where
563     pr = panic "MachCode.getRegister: no primrep needed for Alpha"
564
565 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
566   = case primop of
567       CharGtOp -> trivialCode (CMP LTT) y x
568       CharGeOp -> trivialCode (CMP LE) y x
569       CharEqOp -> trivialCode (CMP EQQ) x y
570       CharNeOp -> int_NE_code x y
571       CharLtOp -> trivialCode (CMP LTT) x y
572       CharLeOp -> trivialCode (CMP LE) x y
573
574       IntGtOp  -> trivialCode (CMP LTT) y x
575       IntGeOp  -> trivialCode (CMP LE) y x
576       IntEqOp  -> trivialCode (CMP EQQ) x y
577       IntNeOp  -> int_NE_code x y
578       IntLtOp  -> trivialCode (CMP LTT) x y
579       IntLeOp  -> trivialCode (CMP LE) x y
580
581       WordGtOp -> trivialCode (CMP ULT) y x
582       WordGeOp -> trivialCode (CMP ULE) x y
583       WordEqOp -> trivialCode (CMP EQQ)  x y
584       WordNeOp -> int_NE_code x y
585       WordLtOp -> trivialCode (CMP ULT) x y
586       WordLeOp -> trivialCode (CMP ULE) x y
587
588       AddrGtOp -> trivialCode (CMP ULT) y x
589       AddrGeOp -> trivialCode (CMP ULE) y x
590       AddrEqOp -> trivialCode (CMP EQQ)  x y
591       AddrNeOp -> int_NE_code x y
592       AddrLtOp -> trivialCode (CMP ULT) x y
593       AddrLeOp -> trivialCode (CMP ULE) x y
594         
595       FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
596       FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
597       FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
598       FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
599       FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
600       FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
601
602       DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
603       DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
604       DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
605       DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
606       DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
607       DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
608
609       IntAddOp  -> trivialCode (ADD Q False) x y
610       IntSubOp  -> trivialCode (SUB Q False) x y
611       IntMulOp  -> trivialCode (MUL Q False) x y
612       IntQuotOp -> trivialCode (DIV Q False) x y
613       IntRemOp  -> trivialCode (REM Q False) x y
614
615       WordAddOp  -> trivialCode (ADD Q False) x y
616       WordSubOp  -> trivialCode (SUB Q False) x y
617       WordMulOp  -> trivialCode (MUL Q False) x y
618       WordQuotOp -> trivialCode (DIV Q True) x y
619       WordRemOp  -> trivialCode (REM Q True) x y
620
621       FloatAddOp -> trivialFCode  FloatRep (FADD TF) x y
622       FloatSubOp -> trivialFCode  FloatRep (FSUB TF) x y
623       FloatMulOp -> trivialFCode  FloatRep (FMUL TF) x y
624       FloatDivOp -> trivialFCode  FloatRep (FDIV TF) x y
625
626       DoubleAddOp -> trivialFCode  F64 (FADD TF) x y
627       DoubleSubOp -> trivialFCode  F64 (FSUB TF) x y
628       DoubleMulOp -> trivialFCode  F64 (FMUL TF) x y
629       DoubleDivOp -> trivialFCode  F64 (FDIV TF) x y
630
631       AddrAddOp  -> trivialCode (ADD Q False) x y
632       AddrSubOp  -> trivialCode (SUB Q False) x y
633       AddrRemOp  -> trivialCode (REM Q True) x y
634
635       AndOp  -> trivialCode AND x y
636       OrOp   -> trivialCode OR  x y
637       XorOp  -> trivialCode XOR x y
638       SllOp  -> trivialCode SLL x y
639       SrlOp  -> trivialCode SRL x y
640
641       ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
642       ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
643       ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
644
645       FloatPowerOp  -> getRegister (StCall FSLIT("pow") CCallConv F64 [x,y])
646       DoublePowerOp -> getRegister (StCall FSLIT("pow") CCallConv F64 [x,y])
647   where
648     {- ------------------------------------------------------------
649         Some bizarre special code for getting condition codes into
650         registers.  Integer non-equality is a test for equality
651         followed by an XOR with 1.  (Integer comparisons always set
652         the result register to 0 or 1.)  Floating point comparisons of
653         any kind leave the result in a floating point register, so we
654         need to wrangle an integer register out of things.
655     -}
656     int_NE_code :: StixTree -> StixTree -> NatM Register
657
658     int_NE_code x y
659       = trivialCode (CMP EQQ) x y       `thenNat` \ register ->
660         getNewRegNat IntRep             `thenNat` \ tmp ->
661         let
662             code = registerCode register tmp
663             src  = registerName register tmp
664             code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
665         in
666         return (Any IntRep code__2)
667
668     {- ------------------------------------------------------------
669         Comments for int_NE_code also apply to cmpF_code
670     -}
671     cmpF_code
672         :: (Reg -> Reg -> Reg -> Instr)
673         -> Cond
674         -> StixTree -> StixTree
675         -> NatM Register
676
677     cmpF_code instr cond x y
678       = trivialFCode pr instr x y       `thenNat` \ register ->
679         getNewRegNat F64                `thenNat` \ tmp ->
680         getBlockIdNat                   `thenNat` \ lbl ->
681         let
682             code = registerCode register tmp
683             result  = registerName register tmp
684
685             code__2 dst = code . mkSeqInstrs [
686                 OR zeroh (RIImm (ImmInt 1)) dst,
687                 BF cond  result (ImmCLbl lbl),
688                 OR zeroh (RIReg zeroh) dst,
689                 NEWBLOCK lbl]
690         in
691         return (Any IntRep code__2)
692       where
693         pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
694       ------------------------------------------------------------
695
696 getRegister (CmmLoad pk mem)
697   = getAmode mem                    `thenNat` \ amode ->
698     let
699         code = amodeCode amode
700         src   = amodeAddr amode
701         size = primRepToSize pk
702         code__2 dst = code . mkSeqInstr (LD size dst src)
703     in
704     return (Any pk code__2)
705
706 getRegister (StInt i)
707   | fits8Bits i
708   = let
709         code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
710     in
711     return (Any IntRep code)
712   | otherwise
713   = let
714         code dst = mkSeqInstr (LDI Q dst src)
715     in
716     return (Any IntRep code)
717   where
718     src = ImmInt (fromInteger i)
719
720 getRegister leaf
721   | isJust imm
722   = let
723         code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
724     in
725     return (Any PtrRep code)
726   where
727     imm = maybeImm leaf
728     imm__2 = case imm of Just x -> x
729
730 #endif /* alpha_TARGET_ARCH */
731
732 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
733
734 #if i386_TARGET_ARCH
735
736 getRegister (CmmLit (CmmFloat f F32)) = do
737     lbl <- getNewLabelNat
738     let code dst = toOL [
739             LDATA ReadOnlyData
740                         [CmmDataLabel lbl,
741                          CmmStaticLit (CmmFloat f F32)],
742             GLD F32 (ImmAddr (ImmCLbl lbl) 0) dst
743             ]
744     -- in
745     return (Any F32 code)
746
747
748 getRegister (CmmLit (CmmFloat d F64))
749   | d == 0.0
750   = let code dst = unitOL (GLDZ dst)
751     in  return (Any F64 code)
752
753   | d == 1.0
754   = let code dst = unitOL (GLD1 dst)
755     in  return (Any F64 code)
756
757   | otherwise = do
758     lbl <- getNewLabelNat
759     let code dst = toOL [
760             LDATA ReadOnlyData
761                         [CmmDataLabel lbl,
762                          CmmStaticLit (CmmFloat d F64)],
763             GLD F64 (ImmAddr (ImmCLbl lbl) 0) dst
764             ]
765     -- in
766     return (Any F64 code)
767
768 #endif /* i386_TARGET_ARCH */
769
770 #if x86_64_TARGET_ARCH
771
772 getRegister (CmmLit (CmmFloat 0.0 rep)) = do
773    let code dst = unitOL  (XOR rep (OpReg dst) (OpReg dst))
774         -- I don't know why there are xorpd, xorps, and pxor instructions.
775         -- They all appear to do the same thing --SDM
776    return (Any rep code)
777
778 getRegister (CmmLit (CmmFloat f rep)) = do
779     lbl <- getNewLabelNat
780     let code dst = toOL [
781             LDATA ReadOnlyData
782                         [CmmDataLabel lbl,
783                          CmmStaticLit (CmmFloat f rep)],
784             MOV rep (OpAddr (ripRel (ImmCLbl lbl))) (OpReg dst)
785             ]
786     -- in
787     return (Any rep code)
788
789 #endif /* x86_64_TARGET_ARCH */
790
791 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
792
793 -- catch simple cases of zero- or sign-extended load
794 getRegister (CmmMachOp (MO_U_Conv I8 I32) [CmmLoad addr _]) = do
795   code <- intLoadCode (MOVZxL I8) addr
796   return (Any I32 code)
797
798 getRegister (CmmMachOp (MO_S_Conv I8 I32) [CmmLoad addr _]) = do
799   code <- intLoadCode (MOVSxL I8) addr
800   return (Any I32 code)
801
802 getRegister (CmmMachOp (MO_U_Conv I16 I32) [CmmLoad addr _]) = do
803   code <- intLoadCode (MOVZxL I16) addr
804   return (Any I32 code)
805
806 getRegister (CmmMachOp (MO_S_Conv I16 I32) [CmmLoad addr _]) = do
807   code <- intLoadCode (MOVSxL I16) addr
808   return (Any I32 code)
809
810 #endif
811
812 #if x86_64_TARGET_ARCH
813
814 -- catch simple cases of zero- or sign-extended load
815 getRegister (CmmMachOp (MO_U_Conv I8 I64) [CmmLoad addr _]) = do
816   code <- intLoadCode (MOVZxL I8) addr
817   return (Any I64 code)
818
819 getRegister (CmmMachOp (MO_S_Conv I8 I64) [CmmLoad addr _]) = do
820   code <- intLoadCode (MOVSxL I8) addr
821   return (Any I64 code)
822
823 getRegister (CmmMachOp (MO_U_Conv I16 I64) [CmmLoad addr _]) = do
824   code <- intLoadCode (MOVZxL I16) addr
825   return (Any I64 code)
826
827 getRegister (CmmMachOp (MO_S_Conv I16 I64) [CmmLoad addr _]) = do
828   code <- intLoadCode (MOVSxL I16) addr
829   return (Any I64 code)
830
831 getRegister (CmmMachOp (MO_U_Conv I32 I64) [CmmLoad addr _]) = do
832   code <- intLoadCode (MOV I32) addr -- 32-bit loads zero-extend
833   return (Any I64 code)
834
835 getRegister (CmmMachOp (MO_S_Conv I32 I64) [CmmLoad addr _]) = do
836   code <- intLoadCode (MOVSxL I32) addr
837   return (Any I64 code)
838
839 #endif
840
841 #if x86_64_TARGET_ARCH
842 getRegister (CmmMachOp (MO_S_Neg F32) [x]) = do
843   x_code <- getAnyReg x
844   lbl <- getNewLabelNat
845   let
846     code dst = x_code dst `appOL` toOL [
847         -- This is how gcc does it, so it can't be that bad:
848         LDATA ReadOnlyData16 [
849                 CmmAlign 16,
850                 CmmDataLabel lbl,
851                 CmmStaticLit (CmmInt 0x80000000 I32),
852                 CmmStaticLit (CmmInt 0 I32),
853                 CmmStaticLit (CmmInt 0 I32),
854                 CmmStaticLit (CmmInt 0 I32)
855         ],
856         XOR F32 (OpAddr (ripRel (ImmCLbl lbl))) (OpReg dst)
857                 -- xorps, so we need the 128-bit constant
858                 -- ToDo: rip-relative
859         ]
860   --
861   return (Any F32 code)
862
863 getRegister (CmmMachOp (MO_S_Neg F64) [x]) = do
864   x_code <- getAnyReg x
865   lbl <- getNewLabelNat
866   let
867         -- This is how gcc does it, so it can't be that bad:
868     code dst = x_code dst `appOL` toOL [
869         LDATA ReadOnlyData16 [
870                 CmmAlign 16,
871                 CmmDataLabel lbl,
872                 CmmStaticLit (CmmInt 0x8000000000000000 I64),
873                 CmmStaticLit (CmmInt 0 I64)
874         ],
875                 -- gcc puts an unpck here.  Wonder if we need it.
876         XOR F64 (OpAddr (ripRel (ImmCLbl lbl))) (OpReg dst)
877                 -- xorpd, so we need the 128-bit constant
878         ]
879   --
880   return (Any F64 code)
881 #endif
882
883 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
884
885 getRegister (CmmMachOp mop [x]) -- unary MachOps
886   = case mop of
887 #if i386_TARGET_ARCH
888       MO_S_Neg F32 -> trivialUFCode F32 (GNEG F32) x
889       MO_S_Neg F64 -> trivialUFCode F64 (GNEG F64) x
890 #endif
891
892       MO_S_Neg rep -> trivialUCode rep (NEGI rep) x
893       MO_Not rep   -> trivialUCode rep (NOT  rep) x
894
895       -- Nop conversions
896       -- TODO: these are only nops if the arg is not a fixed register that
897       -- can't be byte-addressed.
898       MO_U_Conv I32 I8  -> conversionNop I32 x
899       MO_S_Conv I32 I8  -> conversionNop I32 x
900       MO_U_Conv I16 I8  -> conversionNop I16 x
901       MO_S_Conv I16 I8  -> conversionNop I16 x
902       MO_U_Conv I32 I16 -> conversionNop I32 x
903       MO_S_Conv I32 I16 -> conversionNop I32 x
904 #if x86_64_TARGET_ARCH
905       MO_U_Conv I64 I32 -> conversionNop I64 x
906       MO_S_Conv I64 I32 -> conversionNop I64 x
907       MO_U_Conv I64 I16 -> conversionNop I64 x
908       MO_S_Conv I64 I16 -> conversionNop I64 x
909       MO_U_Conv I64 I8  -> conversionNop I64 x
910       MO_S_Conv I64 I8  -> conversionNop I64 x
911 #endif
912
913       MO_U_Conv rep1 rep2 | rep1 == rep2 -> conversionNop rep1 x
914       MO_S_Conv rep1 rep2 | rep1 == rep2 -> conversionNop rep1 x
915
916       -- widenings
917       MO_U_Conv I8  I32 -> integerExtend I8  I32 MOVZxL x
918       MO_U_Conv I16 I32 -> integerExtend I16 I32 MOVZxL x
919       MO_U_Conv I8  I16 -> integerExtend I8  I16 MOVZxL x
920
921       MO_S_Conv I8  I32 -> integerExtend I8  I32 MOVSxL x
922       MO_S_Conv I16 I32 -> integerExtend I16 I32 MOVSxL x
923       MO_S_Conv I8  I16 -> integerExtend I8  I16 MOVSxL x
924
925 #if x86_64_TARGET_ARCH
926       MO_U_Conv I8  I64 -> integerExtend I8  I64 MOVZxL x
927       MO_U_Conv I16 I64 -> integerExtend I16 I64 MOVZxL x
928       MO_U_Conv I32 I64 -> integerExtend I32 I64 MOVZxL x
929       MO_S_Conv I8  I64 -> integerExtend I8  I64 MOVSxL x
930       MO_S_Conv I16 I64 -> integerExtend I16 I64 MOVSxL x
931       MO_S_Conv I32 I64 -> integerExtend I32 I64 MOVSxL x
932         -- for 32-to-64 bit zero extension, amd64 uses an ordinary movl.
933         -- However, we don't want the register allocator to throw it
934         -- away as an unnecessary reg-to-reg move, so we keep it in
935         -- the form of a movzl and print it as a movl later.
936 #endif
937
938 #if i386_TARGET_ARCH
939       MO_S_Conv F32 F64 -> conversionNop F64 x
940       MO_S_Conv F64 F32 -> conversionNop F32 x
941 #else
942       MO_S_Conv F32 F64 -> coerceFP2FP F64 x
943       MO_S_Conv F64 F32 -> coerceFP2FP F32 x
944 #endif
945
946       MO_S_Conv from to
947         | isFloatingRep from -> coerceFP2Int from to x
948         | isFloatingRep to   -> coerceInt2FP from to x
949
950       other -> pprPanic "getRegister" (pprMachOp mop)
951    where
952         -- signed or unsigned extension.
953         integerExtend from to instr expr = do
954             (reg,e_code) <- if from == I8 then getByteReg expr
955                                           else getSomeReg expr
956             let 
957                 code dst = 
958                   e_code `snocOL`
959                   instr from (OpReg reg) (OpReg dst)
960             return (Any to code)
961
962         conversionNop new_rep expr
963             = do e_code <- getRegister expr
964                  return (swizzleRegisterRep e_code new_rep)
965
966
967 getRegister e@(CmmMachOp mop [x, y]) -- dyadic MachOps
968   = ASSERT2(cmmExprRep x /= I8, pprExpr e)
969     case mop of
970       MO_Eq F32   -> condFltReg EQQ x y
971       MO_Ne F32   -> condFltReg NE x y
972       MO_S_Gt F32 -> condFltReg GTT x y
973       MO_S_Ge F32 -> condFltReg GE x y
974       MO_S_Lt F32 -> condFltReg LTT x y
975       MO_S_Le F32 -> condFltReg LE x y
976
977       MO_Eq F64   -> condFltReg EQQ x y
978       MO_Ne F64   -> condFltReg NE x y
979       MO_S_Gt F64 -> condFltReg GTT x y
980       MO_S_Ge F64 -> condFltReg GE x y
981       MO_S_Lt F64 -> condFltReg LTT x y
982       MO_S_Le F64 -> condFltReg LE x y
983
984       MO_Eq rep   -> condIntReg EQQ x y
985       MO_Ne rep   -> condIntReg NE x y
986
987       MO_S_Gt rep -> condIntReg GTT x y
988       MO_S_Ge rep -> condIntReg GE x y
989       MO_S_Lt rep -> condIntReg LTT x y
990       MO_S_Le rep -> condIntReg LE x y
991
992       MO_U_Gt rep -> condIntReg GU  x y
993       MO_U_Ge rep -> condIntReg GEU x y
994       MO_U_Lt rep -> condIntReg LU  x y
995       MO_U_Le rep -> condIntReg LEU x y
996
997 #if i386_TARGET_ARCH
998       MO_Add F32 -> trivialFCode F32 GADD x y
999       MO_Sub F32 -> trivialFCode F32 GSUB x y
1000
1001       MO_Add F64 -> trivialFCode F64 GADD x y
1002       MO_Sub F64 -> trivialFCode F64 GSUB x y
1003
1004       MO_S_Quot F32 -> trivialFCode F32 GDIV x y
1005       MO_S_Quot F64 -> trivialFCode F64 GDIV x y
1006 #endif
1007
1008 #if x86_64_TARGET_ARCH
1009       MO_Add F32 -> trivialFCode F32 ADD x y
1010       MO_Sub F32 -> trivialFCode F32 SUB x y
1011
1012       MO_Add F64 -> trivialFCode F64 ADD x y
1013       MO_Sub F64 -> trivialFCode F64 SUB x y
1014
1015       MO_S_Quot F32 -> trivialFCode F32 FDIV x y
1016       MO_S_Quot F64 -> trivialFCode F64 FDIV x y
1017 #endif
1018
1019       MO_Add rep -> add_code rep x y
1020       MO_Sub rep -> sub_code rep x y
1021
1022       MO_S_Quot rep -> div_code rep True  True  x y
1023       MO_S_Rem  rep -> div_code rep True  False x y
1024       MO_U_Quot rep -> div_code rep False True  x y
1025       MO_U_Rem  rep -> div_code rep False False x y
1026
1027 #if i386_TARGET_ARCH
1028       MO_Mul   F32 -> trivialFCode F32 GMUL x y
1029       MO_Mul   F64 -> trivialFCode F64 GMUL x y
1030 #endif
1031
1032 #if x86_64_TARGET_ARCH
1033       MO_Mul   F32 -> trivialFCode F32 MUL x y
1034       MO_Mul   F64 -> trivialFCode F64 MUL x y
1035 #endif
1036
1037       MO_Mul   rep -> let op = IMUL rep in 
1038                       trivialCode rep op (Just op) x y
1039
1040       MO_S_MulMayOflo rep -> imulMayOflo rep x y
1041
1042       MO_And rep -> let op = AND rep in 
1043                     trivialCode rep op (Just op) x y
1044       MO_Or  rep -> let op = OR  rep in
1045                     trivialCode rep op (Just op) x y
1046       MO_Xor rep -> let op = XOR rep in
1047                     trivialCode rep op (Just op) x y
1048
1049         {- Shift ops on x86s have constraints on their source, it
1050            either has to be Imm, CL or 1
1051             => trivialCode is not restrictive enough (sigh.)
1052         -}         
1053       MO_Shl rep   -> shift_code rep (SHL rep) x y {-False-}
1054       MO_U_Shr rep -> shift_code rep (SHR rep) x y {-False-}
1055       MO_S_Shr rep -> shift_code rep (SAR rep) x y {-False-}
1056
1057       other -> pprPanic "getRegister(x86) - binary CmmMachOp (1)" (pprMachOp mop)
1058   where
1059     --------------------
1060     imulMayOflo :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
1061     imulMayOflo rep a b = do
1062          (a_reg, a_code) <- getNonClobberedReg a
1063          b_code <- getAnyReg b
1064          let 
1065              shift_amt  = case rep of
1066                            I32 -> 31
1067                            I64 -> 63
1068                            _ -> panic "shift_amt"
1069
1070              code = a_code `appOL` b_code eax `appOL`
1071                         toOL [
1072                            IMUL2 rep (OpReg a_reg),   -- result in %edx:%eax
1073                            SAR rep (OpImm (ImmInt shift_amt)) (OpReg eax),
1074                                 -- sign extend lower part
1075                            SUB rep (OpReg edx) (OpReg eax)
1076                                 -- compare against upper
1077                            -- eax==0 if high part == sign extended low part
1078                         ]
1079          -- in
1080          return (Fixed rep eax code)
1081
1082     --------------------
1083     shift_code :: MachRep
1084                -> (Operand -> Operand -> Instr)
1085                -> CmmExpr
1086                -> CmmExpr
1087                -> NatM Register
1088
1089     {- Case1: shift length as immediate -}
1090     shift_code rep instr x y@(CmmLit lit) = do
1091           x_code <- getAnyReg x
1092           let
1093                code dst
1094                   = x_code dst `snocOL` 
1095                     instr (OpImm (litToImm lit)) (OpReg dst)
1096           -- in
1097           return (Any rep code)
1098         
1099     {- Case2: shift length is complex (non-immediate) -}
1100     shift_code rep instr x y{-amount-} = do
1101         (x_reg, x_code) <- getNonClobberedReg x
1102         y_code <- getAnyReg y
1103         let 
1104            code = x_code `appOL`
1105                   y_code ecx `snocOL`
1106                   instr (OpReg ecx) (OpReg x_reg)
1107         -- in
1108         return (Fixed rep x_reg code)
1109
1110     --------------------
1111     add_code :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
1112     add_code rep x (CmmLit (CmmInt y _)) = add_int rep x y
1113     add_code rep x y = trivialCode rep (ADD rep) (Just (ADD rep)) x y
1114
1115     --------------------
1116     sub_code :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
1117     sub_code rep x (CmmLit (CmmInt y _)) = add_int rep x (-y)
1118     sub_code rep x y = trivialCode rep (SUB rep) Nothing x y
1119
1120     -- our three-operand add instruction:
1121     add_int rep x y = do
1122         (x_reg, x_code) <- getSomeReg x
1123         let
1124             imm = ImmInt (fromInteger y)
1125             code dst
1126                = x_code `snocOL`
1127                  LEA rep
1128                         (OpAddr (AddrBaseIndex (EABaseReg x_reg) EAIndexNone imm))
1129                         (OpReg dst)
1130         -- 
1131         return (Any rep code)
1132
1133     ----------------------
1134     div_code rep signed quotient x y = do
1135            (y_op, y_code) <- getRegOrMem y -- cannot be clobbered
1136            x_code <- getAnyReg x
1137            let
1138              widen | signed    = CLTD rep
1139                    | otherwise = XOR rep (OpReg edx) (OpReg edx)
1140
1141              instr | signed    = IDIV
1142                    | otherwise = DIV
1143
1144              code = y_code `appOL`
1145                     x_code eax `appOL`
1146                     toOL [widen, instr rep y_op]
1147
1148              result | quotient  = eax
1149                     | otherwise = edx
1150
1151            -- in
1152            return (Fixed rep result code)
1153
1154
1155 getRegister (CmmLoad mem pk)
1156   | isFloatingRep pk
1157   = do
1158     Amode src mem_code <- getAmode mem
1159     let
1160         code dst = mem_code `snocOL` 
1161                    IF_ARCH_i386(GLD pk src dst,
1162                                 MOV pk (OpAddr src) (OpReg dst))
1163     --
1164     return (Any pk code)
1165
1166 #if i386_TARGET_ARCH
1167 getRegister (CmmLoad mem pk)
1168   | pk /= I64
1169   = do 
1170     code <- intLoadCode (instr pk) mem
1171     return (Any pk code)
1172   where
1173         instr I8  = MOVZxL pk
1174         instr I16 = MOV I16
1175         instr I32 = MOV I32
1176         -- we always zero-extend 8-bit loads, if we
1177         -- can't think of anything better.  This is because
1178         -- we can't guarantee access to an 8-bit variant of every register
1179         -- (esi and edi don't have 8-bit variants), so to make things
1180         -- simpler we do our 8-bit arithmetic with full 32-bit registers.
1181 #endif
1182
1183 #if x86_64_TARGET_ARCH
1184 -- Simpler memory load code on x86_64
1185 getRegister (CmmLoad mem pk)
1186   = do 
1187     code <- intLoadCode (MOV pk) mem
1188     return (Any pk code)
1189 #endif
1190
1191 getRegister (CmmLit (CmmInt 0 rep))
1192   = let
1193         -- x86_64: 32-bit xor is one byte shorter, and zero-extends to 64 bits
1194         adj_rep = case rep of I64 -> I32; _ -> rep
1195         rep1 = IF_ARCH_i386( rep, adj_rep ) 
1196         code dst 
1197            = unitOL (XOR rep1 (OpReg dst) (OpReg dst))
1198     in
1199         return (Any rep code)
1200
1201 #if x86_64_TARGET_ARCH
1202   -- optimisation for loading small literals on x86_64: take advantage
1203   -- of the automatic zero-extension from 32 to 64 bits, because the 32-bit
1204   -- instruction forms are shorter.
1205 getRegister (CmmLit lit) 
1206   | I64 <- cmmLitRep lit, not (isBigLit lit)
1207   = let 
1208         imm = litToImm lit
1209         code dst = unitOL (MOV I32 (OpImm imm) (OpReg dst))
1210     in
1211         return (Any I64 code)
1212   where
1213    isBigLit (CmmInt i I64) = i < 0 || i > 0xffffffff
1214    isBigLit _ = False
1215         -- note1: not the same as is64BitLit, because that checks for
1216         -- signed literals that fit in 32 bits, but we want unsigned
1217         -- literals here.
1218         -- note2: all labels are small, because we're assuming the
1219         -- small memory model (see gcc docs, -mcmodel=small).
1220 #endif
1221
1222 getRegister (CmmLit lit)
1223   = let 
1224         rep = cmmLitRep lit
1225         imm = litToImm lit
1226         code dst = unitOL (MOV rep (OpImm imm) (OpReg dst))
1227     in
1228         return (Any rep code)
1229
1230 getRegister other = pprPanic "getRegister(x86)" (ppr other)
1231
1232
1233 intLoadCode :: (Operand -> Operand -> Instr) -> CmmExpr
1234    -> NatM (Reg -> InstrBlock)
1235 intLoadCode instr mem = do
1236   Amode src mem_code <- getAmode mem
1237   return (\dst -> mem_code `snocOL` instr (OpAddr src) (OpReg dst))
1238
1239 -- Compute an expression into *any* register, adding the appropriate
1240 -- move instruction if necessary.
1241 getAnyReg :: CmmExpr -> NatM (Reg -> InstrBlock)
1242 getAnyReg expr = do
1243   r <- getRegister expr
1244   anyReg r
1245
1246 anyReg :: Register -> NatM (Reg -> InstrBlock)
1247 anyReg (Any _ code)          = return code
1248 anyReg (Fixed rep reg fcode) = return (\dst -> fcode `snocOL` reg2reg rep reg dst)
1249
1250 -- A bit like getSomeReg, but we want a reg that can be byte-addressed.
1251 -- Fixed registers might not be byte-addressable, so we make sure we've
1252 -- got a temporary, inserting an extra reg copy if necessary.
1253 getByteReg :: CmmExpr -> NatM (Reg, InstrBlock)
1254 #if x86_64_TARGET_ARCH
1255 getByteReg = getSomeReg -- all regs are byte-addressable on x86_64
1256 #else
1257 getByteReg expr = do
1258   r <- getRegister expr
1259   case r of
1260     Any rep code -> do
1261         tmp <- getNewRegNat rep
1262         return (tmp, code tmp)
1263     Fixed rep reg code 
1264         | isVirtualReg reg -> return (reg,code)
1265         | otherwise -> do
1266             tmp <- getNewRegNat rep
1267             return (tmp, code `snocOL` reg2reg rep reg tmp)
1268         -- ToDo: could optimise slightly by checking for byte-addressable
1269         -- real registers, but that will happen very rarely if at all.
1270 #endif
1271
1272 -- Another variant: this time we want the result in a register that cannot
1273 -- be modified by code to evaluate an arbitrary expression.
1274 getNonClobberedReg :: CmmExpr -> NatM (Reg, InstrBlock)
1275 getNonClobberedReg expr = do
1276   r <- getRegister expr
1277   case r of
1278     Any rep code -> do
1279         tmp <- getNewRegNat rep
1280         return (tmp, code tmp)
1281     Fixed rep reg code
1282         -- only free regs can be clobbered
1283         | RealReg rr <- reg, isFastTrue (freeReg rr) -> do
1284                 tmp <- getNewRegNat rep
1285                 return (tmp, code `snocOL` reg2reg rep reg tmp)
1286         | otherwise -> 
1287                 return (reg, code)
1288
1289 reg2reg :: MachRep -> Reg -> Reg -> Instr
1290 reg2reg rep src dst 
1291 #if i386_TARGET_ARCH
1292   | isFloatingRep rep = GMOV src dst
1293 #endif
1294   | otherwise         = MOV rep (OpReg src) (OpReg dst)
1295
1296 #endif /* i386_TARGET_ARCH || x86_64_TARGET_ARCH */
1297
1298 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1299
1300 #if sparc_TARGET_ARCH
1301
1302 getRegister (CmmLit (CmmFloat f F32)) = do
1303     lbl <- getNewLabelNat
1304     let code dst = toOL [
1305             LDATA ReadOnlyData
1306                         [CmmDataLabel lbl,
1307                          CmmStaticLit (CmmFloat f F32)],
1308             SETHI (HI (ImmCLbl lbl)) dst,
1309             LD F32 (AddrRegImm dst (LO (ImmCLbl lbl))) dst] 
1310     return (Any F32 code)
1311
1312 getRegister (CmmLit (CmmFloat d F64)) = do
1313     lbl <- getNewLabelNat
1314     let code dst = toOL [
1315             LDATA ReadOnlyData
1316                         [CmmDataLabel lbl,
1317                          CmmStaticLit (CmmFloat d F64)],
1318             SETHI (HI (ImmCLbl lbl)) dst,
1319             LD F64 (AddrRegImm dst (LO (ImmCLbl lbl))) dst] 
1320     return (Any F64 code)
1321
1322 getRegister (CmmMachOp mop [x]) -- unary MachOps
1323   = case mop of
1324       MO_S_Neg F32     -> trivialUFCode F32 (FNEG F32) x
1325       MO_S_Neg F64     -> trivialUFCode F64 (FNEG F64) x
1326
1327       MO_S_Neg rep     -> trivialUCode rep (SUB False False g0) x
1328       MO_Not rep       -> trivialUCode rep (XNOR False g0) x
1329
1330       MO_U_Conv I32 I8 -> trivialCode I8 (AND False) x (CmmLit (CmmInt 255 I8))
1331
1332       MO_U_Conv F64 F32-> coerceDbl2Flt x
1333       MO_U_Conv F32 F64-> coerceFlt2Dbl x
1334
1335       MO_S_Conv F32 I32-> coerceFP2Int F32 I32 x
1336       MO_S_Conv I32 F32-> coerceInt2FP I32 F32 x
1337       MO_S_Conv F64 I32-> coerceFP2Int F64 I32 x
1338       MO_S_Conv I32 F64-> coerceInt2FP I32 F64 x
1339
1340       -- Conversions which are a nop on sparc
1341       MO_U_Conv from to
1342         | from == to   -> conversionNop to   x
1343       MO_U_Conv I32 to -> conversionNop to   x
1344       MO_S_Conv I32 to -> conversionNop to   x
1345
1346       -- widenings
1347       MO_U_Conv I8 I32  -> integerExtend False I8 I32  x
1348       MO_U_Conv I16 I32 -> integerExtend False I16 I32 x
1349       MO_U_Conv I8 I16  -> integerExtend False I8 I16  x
1350       MO_S_Conv I16 I32 -> integerExtend True I16 I32  x
1351
1352       other_op -> panic "Unknown unary mach op"
1353     where
1354         -- XXX SLL/SRL?
1355         integerExtend signed from to expr = do
1356            (reg, e_code) <- getSomeReg expr
1357            let
1358                code dst =
1359                    e_code `snocOL` 
1360                    ((if signed then SRA else SRL)
1361                           reg (RIImm (ImmInt 0)) dst)
1362            return (Any to code)
1363         conversionNop new_rep expr
1364             = do e_code <- getRegister expr
1365                  return (swizzleRegisterRep e_code new_rep)
1366
1367 getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
1368   = case mop of
1369       MO_Eq F32 -> condFltReg EQQ x y
1370       MO_Ne F32 -> condFltReg NE x y
1371
1372       MO_S_Gt F32 -> condFltReg GTT x y
1373       MO_S_Ge F32 -> condFltReg GE x y 
1374       MO_S_Lt F32 -> condFltReg LTT x y
1375       MO_S_Le F32 -> condFltReg LE x y
1376
1377       MO_Eq F64 -> condFltReg EQQ x y
1378       MO_Ne F64 -> condFltReg NE x y
1379
1380       MO_S_Gt F64 -> condFltReg GTT x y
1381       MO_S_Ge F64 -> condFltReg GE x y
1382       MO_S_Lt F64 -> condFltReg LTT x y
1383       MO_S_Le F64 -> condFltReg LE x y
1384
1385       MO_Eq rep -> condIntReg EQQ x y
1386       MO_Ne rep -> condIntReg NE x y
1387
1388       MO_S_Gt rep -> condIntReg GTT x y
1389       MO_S_Ge rep -> condIntReg GE x y
1390       MO_S_Lt rep -> condIntReg LTT x y
1391       MO_S_Le rep -> condIntReg LE x y
1392               
1393       MO_U_Gt I32  -> condIntReg GTT x y
1394       MO_U_Ge I32  -> condIntReg GE x y
1395       MO_U_Lt I32  -> condIntReg LTT x y
1396       MO_U_Le I32  -> condIntReg LE x y
1397
1398       MO_U_Gt I16 -> condIntReg GU  x y
1399       MO_U_Ge I16 -> condIntReg GEU x y
1400       MO_U_Lt I16 -> condIntReg LU  x y
1401       MO_U_Le I16 -> condIntReg LEU x y
1402
1403       MO_Add I32 -> trivialCode I32 (ADD False False) x y
1404       MO_Sub I32 -> trivialCode I32 (SUB False False) x y
1405
1406       MO_S_MulMayOflo rep -> imulMayOflo rep x y
1407 {-
1408       -- ToDo: teach about V8+ SPARC div instructions
1409       MO_S_Quot I32 -> idiv FSLIT(".div")  x y
1410       MO_S_Rem I32  -> idiv FSLIT(".rem")  x y
1411       MO_U_Quot I32 -> idiv FSLIT(".udiv")  x y
1412       MO_U_Rem I32  -> idiv FSLIT(".urem")  x y
1413 -}
1414       MO_Add F32  -> trivialFCode F32 FADD  x y
1415       MO_Sub F32   -> trivialFCode F32  FSUB x y
1416       MO_Mul F32   -> trivialFCode F32  FMUL  x y
1417       MO_S_Quot F32   -> trivialFCode F32  FDIV x y
1418
1419       MO_Add F64   -> trivialFCode F64 FADD  x y
1420       MO_Sub F64   -> trivialFCode F64  FSUB x y
1421       MO_Mul F64   -> trivialFCode F64  FMUL x y
1422       MO_S_Quot F64   -> trivialFCode F64  FDIV x y
1423
1424       MO_And rep   -> trivialCode rep (AND False) x y
1425       MO_Or rep    -> trivialCode rep (OR  False) x y
1426       MO_Xor rep   -> trivialCode rep (XOR False) x y
1427
1428       MO_Mul rep -> trivialCode rep (SMUL False) x y
1429
1430       MO_Shl rep   -> trivialCode rep SLL  x y
1431       MO_U_Shr rep   -> trivialCode rep SRL x y
1432       MO_S_Shr rep   -> trivialCode rep SRA x y
1433
1434 {-
1435       MO_F32_Pwr  -> getRegister (StCall (Left FSLIT("pow")) CCallConv F64 
1436                                          [promote x, promote y])
1437                        where promote x = CmmMachOp MO_F32_to_Dbl [x]
1438       MO_F64_Pwr -> getRegister (StCall (Left FSLIT("pow")) CCallConv F64 
1439                                         [x, y])
1440 -}
1441       other -> pprPanic "getRegister(sparc) - binary CmmMachOp (1)" (pprMachOp mop)
1442   where
1443     --idiv fn x y = getRegister (StCall (Left fn) CCallConv I32 [x, y])
1444
1445     --------------------
1446     imulMayOflo :: MachRep -> CmmExpr -> CmmExpr -> NatM Register
1447     imulMayOflo rep a b = do
1448          (a_reg, a_code) <- getSomeReg a
1449          (b_reg, b_code) <- getSomeReg b
1450          res_lo <- getNewRegNat I32
1451          res_hi <- getNewRegNat I32
1452          let
1453             shift_amt  = case rep of
1454                           I32 -> 31
1455                           I64 -> 63
1456                           _ -> panic "shift_amt"
1457             code dst = a_code `appOL` b_code `appOL`
1458                        toOL [
1459                            SMUL False a_reg (RIReg b_reg) res_lo,
1460                            RDY res_hi,
1461                            SRA res_lo (RIImm (ImmInt shift_amt)) res_lo,
1462                            SUB False False res_lo (RIReg res_hi) dst
1463                         ]
1464          return (Any I32 code)
1465
1466 getRegister (CmmLoad mem pk) = do
1467     Amode src code <- getAmode mem
1468     let
1469         code__2 dst = code `snocOL` LD pk src dst
1470     return (Any pk code__2)
1471
1472 getRegister (CmmLit (CmmInt i _))
1473   | fits13Bits i
1474   = let
1475         src = ImmInt (fromInteger i)
1476         code dst = unitOL (OR False g0 (RIImm src) dst)
1477     in
1478         return (Any I32 code)
1479
1480 getRegister (CmmLit lit)
1481   = let rep = cmmLitRep lit
1482         imm = litToImm lit
1483         code dst = toOL [
1484             SETHI (HI imm) dst,
1485             OR False dst (RIImm (LO imm)) dst]
1486     in return (Any I32 code)
1487
1488 #endif /* sparc_TARGET_ARCH */
1489
1490 #if powerpc_TARGET_ARCH
1491 getRegister (CmmLoad mem pk)
1492   | pk /= I64
1493   = do
1494         Amode addr addr_code <- getAmode mem
1495         let code dst = ASSERT((regClass dst == RcDouble) == isFloatingRep pk)
1496                        addr_code `snocOL` LD pk dst addr
1497         return (Any pk code)
1498
1499 -- catch simple cases of zero- or sign-extended load
1500 getRegister (CmmMachOp (MO_U_Conv I8 I32) [CmmLoad mem _]) = do
1501     Amode addr addr_code <- getAmode mem
1502     return (Any I32 (\dst -> addr_code `snocOL` LD I8 dst addr))
1503
1504 -- Note: there is no Load Byte Arithmetic instruction, so no signed case here
1505
1506 getRegister (CmmMachOp (MO_U_Conv I16 I32) [CmmLoad mem _]) = do
1507     Amode addr addr_code <- getAmode mem
1508     return (Any I32 (\dst -> addr_code `snocOL` LD I16 dst addr))
1509
1510 getRegister (CmmMachOp (MO_S_Conv I16 I32) [CmmLoad mem _]) = do
1511     Amode addr addr_code <- getAmode mem
1512     return (Any I32 (\dst -> addr_code `snocOL` LA I16 dst addr))
1513
1514 getRegister (CmmMachOp mop [x]) -- unary MachOps
1515   = case mop of
1516       MO_Not rep   -> trivialUCode rep NOT x
1517
1518       MO_S_Conv F64 F32 -> trivialUCode F32 FRSP x
1519       MO_S_Conv F32 F64 -> conversionNop F64 x
1520
1521       MO_S_Conv from to
1522         | from == to         -> conversionNop to x
1523         | isFloatingRep from -> coerceFP2Int from to x
1524         | isFloatingRep to   -> coerceInt2FP from to x
1525
1526         -- narrowing is a nop: we treat the high bits as undefined
1527       MO_S_Conv I32 to -> conversionNop to x
1528       MO_S_Conv I16 I8 -> conversionNop I8 x
1529       MO_S_Conv I8 to -> trivialUCode to (EXTS I8) x
1530       MO_S_Conv I16 to -> trivialUCode to (EXTS I16) x
1531
1532       MO_U_Conv from to
1533         | from == to -> conversionNop to x
1534         -- narrowing is a nop: we treat the high bits as undefined
1535       MO_U_Conv I32 to -> conversionNop to x
1536       MO_U_Conv I16 I8 -> conversionNop I8 x
1537       MO_U_Conv I8 to -> trivialCode to False AND x (CmmLit (CmmInt 255 I32))
1538       MO_U_Conv I16 to -> trivialCode to False AND x (CmmLit (CmmInt 65535 I32)) 
1539
1540       MO_S_Neg F32      -> trivialUCode F32 FNEG x
1541       MO_S_Neg F64      -> trivialUCode F64 FNEG x
1542       MO_S_Neg rep      -> trivialUCode rep NEG x
1543       
1544     where
1545         conversionNop new_rep expr
1546             = do e_code <- getRegister expr
1547                  return (swizzleRegisterRep e_code new_rep)
1548
1549 getRegister (CmmMachOp mop [x, y]) -- dyadic PrimOps
1550   = case mop of
1551       MO_Eq F32 -> condFltReg EQQ x y
1552       MO_Ne F32 -> condFltReg NE  x y
1553
1554       MO_S_Gt F32 -> condFltReg GTT x y
1555       MO_S_Ge F32 -> condFltReg GE  x y
1556       MO_S_Lt F32 -> condFltReg LTT x y
1557       MO_S_Le F32 -> condFltReg LE  x y
1558
1559       MO_Eq F64 -> condFltReg EQQ x y
1560       MO_Ne F64 -> condFltReg NE  x y
1561
1562       MO_S_Gt F64 -> condFltReg GTT x y
1563       MO_S_Ge F64 -> condFltReg GE  x y
1564       MO_S_Lt F64 -> condFltReg LTT x y
1565       MO_S_Le F64 -> condFltReg LE  x y
1566
1567       MO_Eq rep -> condIntReg EQQ  (extendUExpr rep x) (extendUExpr rep y)
1568       MO_Ne rep -> condIntReg NE   (extendUExpr rep x) (extendUExpr rep y)
1569
1570       MO_S_Gt rep -> condIntReg GTT  (extendSExpr rep x) (extendSExpr rep y)
1571       MO_S_Ge rep -> condIntReg GE   (extendSExpr rep x) (extendSExpr rep y)
1572       MO_S_Lt rep -> condIntReg LTT  (extendSExpr rep x) (extendSExpr rep y)
1573       MO_S_Le rep -> condIntReg LE   (extendSExpr rep x) (extendSExpr rep y)
1574
1575       MO_U_Gt rep -> condIntReg GU   (extendUExpr rep x) (extendUExpr rep y)
1576       MO_U_Ge rep -> condIntReg GEU  (extendUExpr rep x) (extendUExpr rep y)
1577       MO_U_Lt rep -> condIntReg LU   (extendUExpr rep x) (extendUExpr rep y)
1578       MO_U_Le rep -> condIntReg LEU  (extendUExpr rep x) (extendUExpr rep y)
1579
1580       MO_Add F32   -> trivialCodeNoImm F32 (FADD F32) x y
1581       MO_Sub F32   -> trivialCodeNoImm F32 (FSUB F32) x y
1582       MO_Mul F32   -> trivialCodeNoImm F32 (FMUL F32) x y
1583       MO_S_Quot F32   -> trivialCodeNoImm F32 (FDIV F32) x y
1584       
1585       MO_Add F64   -> trivialCodeNoImm F64 (FADD F64) x y
1586       MO_Sub F64   -> trivialCodeNoImm F64 (FSUB F64) x y
1587       MO_Mul F64   -> trivialCodeNoImm F64 (FMUL F64) x y
1588       MO_S_Quot F64   -> trivialCodeNoImm F64 (FDIV F64) x y
1589
1590          -- optimize addition with 32-bit immediate
1591          -- (needed for PIC)
1592       MO_Add I32 ->
1593         case y of
1594           CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate I32 True (-imm)
1595             -> trivialCode I32 True ADD x (CmmLit $ CmmInt imm immrep)
1596           CmmLit lit
1597             -> do
1598                 (src, srcCode) <- getSomeReg x
1599                 let imm = litToImm lit
1600                     code dst = srcCode `appOL` toOL [
1601                                     ADDIS dst src (HA imm),
1602                                     ADD dst dst (RIImm (LO imm))
1603                                 ]
1604                 return (Any I32 code)
1605           _ -> trivialCode I32 True ADD x y
1606
1607       MO_Add rep -> trivialCode rep True ADD x y
1608       MO_Sub rep ->
1609         case y of    -- subfi ('substract from' with immediate) doesn't exist
1610           CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate rep True (-imm)
1611             -> trivialCode rep True ADD x (CmmLit $ CmmInt (-imm) immrep)
1612           _ -> trivialCodeNoImm rep SUBF y x
1613
1614       MO_Mul rep -> trivialCode rep True MULLW x y
1615
1616       MO_S_MulMayOflo I32 -> trivialCodeNoImm I32 MULLW_MayOflo x y
1617       
1618       MO_S_MulMayOflo rep -> panic "S_MulMayOflo (rep /= I32): not implemented"
1619       MO_U_MulMayOflo rep -> panic "U_MulMayOflo: not implemented"
1620
1621       MO_S_Quot rep -> trivialCodeNoImm rep DIVW (extendSExpr rep x) (extendSExpr rep y)
1622       MO_U_Quot rep -> trivialCodeNoImm rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
1623       
1624       MO_S_Rem rep -> remainderCode rep DIVW (extendSExpr rep x) (extendSExpr rep y)
1625       MO_U_Rem rep -> remainderCode rep DIVWU (extendUExpr rep x) (extendUExpr rep y)
1626       
1627       MO_And rep   -> trivialCode rep False AND x y
1628       MO_Or rep    -> trivialCode rep False OR x y
1629       MO_Xor rep   -> trivialCode rep False XOR x y
1630
1631       MO_Shl rep   -> trivialCode rep False SLW x y
1632       MO_S_Shr rep -> trivialCode rep False SRAW (extendSExpr rep x) y
1633       MO_U_Shr rep -> trivialCode rep False SRW (extendUExpr rep x) y
1634
1635 getRegister (CmmLit (CmmInt i rep))
1636   | Just imm <- makeImmediate rep True i
1637   = let
1638         code dst = unitOL (LI dst imm)
1639     in
1640         return (Any rep code)
1641
1642 getRegister (CmmLit (CmmFloat f frep)) = do
1643     lbl <- getNewLabelNat
1644     dynRef <- cmmMakeDynamicReference addImportNat False lbl
1645     Amode addr addr_code <- getAmode dynRef
1646     let code dst = 
1647             LDATA ReadOnlyData  [CmmDataLabel lbl,
1648                                  CmmStaticLit (CmmFloat f frep)]
1649             `consOL` (addr_code `snocOL` LD frep dst addr)
1650     return (Any frep code)
1651
1652 getRegister (CmmLit lit)
1653   = let rep = cmmLitRep lit
1654         imm = litToImm lit
1655         code dst = toOL [
1656               LIS dst (HI imm),
1657               OR dst dst (RIImm (LO imm))
1658           ]
1659     in return (Any rep code)
1660
1661 getRegister other = pprPanic "getRegister(ppc)" (pprExpr other)
1662     
1663     -- extend?Rep: wrap integer expression of type rep
1664     -- in a conversion to I32
1665 extendSExpr I32 x = x
1666 extendSExpr rep x = CmmMachOp (MO_S_Conv rep I32) [x]
1667 extendUExpr I32 x = x
1668 extendUExpr rep x = CmmMachOp (MO_U_Conv rep I32) [x]
1669
1670 #endif /* powerpc_TARGET_ARCH */
1671
1672
1673 -- -----------------------------------------------------------------------------
1674 --  The 'Amode' type: Memory addressing modes passed up the tree.
1675
1676 data Amode = Amode AddrMode InstrBlock
1677
1678 {-
1679 Now, given a tree (the argument to an CmmLoad) that references memory,
1680 produce a suitable addressing mode.
1681
1682 A Rule of the Game (tm) for Amodes: use of the addr bit must
1683 immediately follow use of the code part, since the code part puts
1684 values in registers which the addr then refers to.  So you can't put
1685 anything in between, lest it overwrite some of those registers.  If
1686 you need to do some other computation between the code part and use of
1687 the addr bit, first store the effective address from the amode in a
1688 temporary, then do the other computation, and then use the temporary:
1689
1690     code
1691     LEA amode, tmp
1692     ... other computation ...
1693     ... (tmp) ...
1694 -}
1695
1696 getAmode :: CmmExpr -> NatM Amode
1697 getAmode tree@(CmmRegOff _ _) = getAmode (mangleIndexTree tree)
1698
1699 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1700
1701 #if alpha_TARGET_ARCH
1702
1703 getAmode (StPrim IntSubOp [x, StInt i])
1704   = getNewRegNat PtrRep         `thenNat` \ tmp ->
1705     getRegister x               `thenNat` \ register ->
1706     let
1707         code = registerCode register tmp
1708         reg  = registerName register tmp
1709         off  = ImmInt (-(fromInteger i))
1710     in
1711     return (Amode (AddrRegImm reg off) code)
1712
1713 getAmode (StPrim IntAddOp [x, StInt i])
1714   = getNewRegNat PtrRep         `thenNat` \ tmp ->
1715     getRegister x               `thenNat` \ register ->
1716     let
1717         code = registerCode register tmp
1718         reg  = registerName register tmp
1719         off  = ImmInt (fromInteger i)
1720     in
1721     return (Amode (AddrRegImm reg off) code)
1722
1723 getAmode leaf
1724   | isJust imm
1725   = return (Amode (AddrImm imm__2) id)
1726   where
1727     imm = maybeImm leaf
1728     imm__2 = case imm of Just x -> x
1729
1730 getAmode other
1731   = getNewRegNat PtrRep         `thenNat` \ tmp ->
1732     getRegister other           `thenNat` \ register ->
1733     let
1734         code = registerCode register tmp
1735         reg  = registerName register tmp
1736     in
1737     return (Amode (AddrReg reg) code)
1738
1739 #endif /* alpha_TARGET_ARCH */
1740
1741 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1742
1743 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
1744
1745 -- This is all just ridiculous, since it carefully undoes 
1746 -- what mangleIndexTree has just done.
1747 getAmode (CmmMachOp (MO_Sub rep) [x, CmmLit lit@(CmmInt i _)])
1748   | not (is64BitLit lit)
1749   -- ASSERT(rep == I32)???
1750   = do (x_reg, x_code) <- getSomeReg x
1751        let off = ImmInt (-(fromInteger i))
1752        return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code)
1753   
1754 getAmode (CmmMachOp (MO_Add rep) [x, CmmLit lit@(CmmInt i _)])
1755   | not (is64BitLit lit)
1756   -- ASSERT(rep == I32)???
1757   = do (x_reg, x_code) <- getSomeReg x
1758        let off = ImmInt (fromInteger i)
1759        return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code)
1760
1761 -- Turn (lit1 << n  + lit2) into  (lit2 + lit1 << n) so it will be 
1762 -- recognised by the next rule.
1763 getAmode (CmmMachOp (MO_Add rep) [a@(CmmMachOp (MO_Shl _) _),
1764                                   b@(CmmLit _)])
1765   = getAmode (CmmMachOp (MO_Add rep) [b,a])
1766
1767 getAmode (CmmMachOp (MO_Add rep) [x, CmmMachOp (MO_Shl _) 
1768                                         [y, CmmLit (CmmInt shift _)]])
1769   | shift == 0 || shift == 1 || shift == 2 || shift == 3
1770   = do (x_reg, x_code) <- getNonClobberedReg x
1771         -- x must be in a temp, because it has to stay live over y_code
1772         -- we could compre x_reg and y_reg and do something better here...
1773        (y_reg, y_code) <- getSomeReg y
1774        let
1775            code = x_code `appOL` y_code
1776            base = case shift of 0 -> 1; 1 -> 2; 2 -> 4; 3 -> 8
1777        return (Amode (AddrBaseIndex (EABaseReg x_reg) (EAIndex y_reg base) (ImmInt 0))
1778                code)
1779
1780 getAmode (CmmLit lit) | not (is64BitLit lit)
1781   = return (Amode (ImmAddr (litToImm lit) 0) nilOL)
1782
1783 getAmode expr = do
1784   (reg,code) <- getSomeReg expr
1785   return (Amode (AddrBaseIndex (EABaseReg reg) EAIndexNone (ImmInt 0)) code)
1786
1787 #endif /* i386_TARGET_ARCH || x86_64_TARGET_ARCH */
1788
1789 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1790
1791 #if sparc_TARGET_ARCH
1792
1793 getAmode (CmmMachOp (MO_Sub rep) [x, CmmLit (CmmInt i _)])
1794   | fits13Bits (-i)
1795   = do
1796        (reg, code) <- getSomeReg x
1797        let
1798          off  = ImmInt (-(fromInteger i))
1799        return (Amode (AddrRegImm reg off) code)
1800
1801
1802 getAmode (CmmMachOp (MO_Add rep) [x, CmmLit (CmmInt i _)])
1803   | fits13Bits i
1804   = do
1805        (reg, code) <- getSomeReg x
1806        let
1807          off  = ImmInt (fromInteger i)
1808        return (Amode (AddrRegImm reg off) code)
1809
1810 getAmode (CmmMachOp (MO_Add rep) [x, y])
1811   = do
1812     (regX, codeX) <- getSomeReg x
1813     (regY, codeY) <- getSomeReg y
1814     let
1815         code = codeX `appOL` codeY
1816     return (Amode (AddrRegReg regX regY) code)
1817
1818 -- XXX Is this same as "leaf" in Stix?
1819 getAmode (CmmLit lit)
1820   = do
1821       tmp <- getNewRegNat I32
1822       let
1823         code = unitOL (SETHI (HI imm__2) tmp)
1824       return (Amode (AddrRegImm tmp (LO imm__2)) code)
1825       where
1826          imm__2 = litToImm lit
1827
1828 getAmode other
1829   = do
1830        (reg, code) <- getSomeReg other
1831        let
1832             off  = ImmInt 0
1833        return (Amode (AddrRegImm reg off) code)
1834
1835 #endif /* sparc_TARGET_ARCH */
1836
1837 #ifdef powerpc_TARGET_ARCH
1838 getAmode (CmmMachOp (MO_Sub I32) [x, CmmLit (CmmInt i _)])
1839   | Just off <- makeImmediate I32 True (-i)
1840   = do
1841         (reg, code) <- getSomeReg x
1842         return (Amode (AddrRegImm reg off) code)
1843
1844
1845 getAmode (CmmMachOp (MO_Add I32) [x, CmmLit (CmmInt i _)])
1846   | Just off <- makeImmediate I32 True i
1847   = do
1848         (reg, code) <- getSomeReg x
1849         return (Amode (AddrRegImm reg off) code)
1850
1851    -- optimize addition with 32-bit immediate
1852    -- (needed for PIC)
1853 getAmode (CmmMachOp (MO_Add I32) [x, CmmLit lit])
1854   = do
1855         tmp <- getNewRegNat I32
1856         (src, srcCode) <- getSomeReg x
1857         let imm = litToImm lit
1858             code = srcCode `snocOL` ADDIS tmp src (HA imm)
1859         return (Amode (AddrRegImm tmp (LO imm)) code)
1860
1861 getAmode (CmmLit lit)
1862   = do
1863         tmp <- getNewRegNat I32
1864         let imm = litToImm lit
1865             code = unitOL (LIS tmp (HA imm))
1866         return (Amode (AddrRegImm tmp (LO imm)) code)
1867     
1868 getAmode (CmmMachOp (MO_Add I32) [x, y])
1869   = do
1870         (regX, codeX) <- getSomeReg x
1871         (regY, codeY) <- getSomeReg y
1872         return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))
1873     
1874 getAmode other
1875   = do
1876         (reg, code) <- getSomeReg other
1877         let
1878             off  = ImmInt 0
1879         return (Amode (AddrRegImm reg off) code)
1880 #endif /* powerpc_TARGET_ARCH */
1881
1882 -- -----------------------------------------------------------------------------
1883 -- getOperand: sometimes any operand will do.
1884
1885 -- getNonClobberedOperand: the value of the operand will remain valid across
1886 -- the computation of an arbitrary expression, unless the expression
1887 -- is computed directly into a register which the operand refers to
1888 -- (see trivialCode where this function is used for an example).
1889
1890 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
1891
1892 getNonClobberedOperand :: CmmExpr -> NatM (Operand, InstrBlock)
1893 #if x86_64_TARGET_ARCH
1894 getNonClobberedOperand (CmmLit lit)
1895   | isSuitableFloatingPointLit lit = do
1896     lbl <- getNewLabelNat
1897     let code = unitOL (LDATA ReadOnlyData  [CmmDataLabel lbl,
1898                                            CmmStaticLit lit])
1899     return (OpAddr (ripRel (ImmCLbl lbl)), code)
1900 #endif
1901 getNonClobberedOperand (CmmLit lit)
1902   | not (is64BitLit lit) && not (isFloatingRep (cmmLitRep lit)) =
1903     return (OpImm (litToImm lit), nilOL)
1904 getNonClobberedOperand (CmmLoad mem pk) 
1905   | IF_ARCH_i386(not (isFloatingRep pk) && pk /= I64, True) = do
1906     Amode src mem_code <- getAmode mem
1907     (src',save_code) <- 
1908         if (amodeCouldBeClobbered src) 
1909                 then do
1910                    tmp <- getNewRegNat wordRep
1911                    return (AddrBaseIndex (EABaseReg tmp) EAIndexNone (ImmInt 0),
1912                            unitOL (LEA I32 (OpAddr src) (OpReg tmp)))
1913                 else
1914                    return (src, nilOL)
1915     return (OpAddr src', save_code `appOL` mem_code)
1916 getNonClobberedOperand e = do
1917     (reg, code) <- getNonClobberedReg e
1918     return (OpReg reg, code)
1919
1920 amodeCouldBeClobbered :: AddrMode -> Bool
1921 amodeCouldBeClobbered amode = any regClobbered (addrModeRegs amode)
1922
1923 regClobbered (RealReg rr) = isFastTrue (freeReg rr)
1924 regClobbered _ = False
1925
1926 -- getOperand: the operand is not required to remain valid across the
1927 -- computation of an arbitrary expression.
1928 getOperand :: CmmExpr -> NatM (Operand, InstrBlock)
1929 #if x86_64_TARGET_ARCH
1930 getOperand (CmmLit lit)
1931   | isSuitableFloatingPointLit lit = do
1932     lbl <- getNewLabelNat
1933     let code = unitOL (LDATA ReadOnlyData  [CmmDataLabel lbl,
1934                                            CmmStaticLit lit])
1935     return (OpAddr (ripRel (ImmCLbl lbl)), code)
1936 #endif
1937 getOperand (CmmLit lit)
1938   | not (is64BitLit lit) && not (isFloatingRep (cmmLitRep lit)) = do
1939     return (OpImm (litToImm lit), nilOL)
1940 getOperand (CmmLoad mem pk)
1941   | IF_ARCH_i386(not (isFloatingRep pk) && pk /= I64, True) = do
1942     Amode src mem_code <- getAmode mem
1943     return (OpAddr src, mem_code)
1944 getOperand e = do
1945     (reg, code) <- getSomeReg e
1946     return (OpReg reg, code)
1947
1948 isOperand :: CmmExpr -> Bool
1949 isOperand (CmmLoad _ _) = True
1950 isOperand (CmmLit lit)  = not (is64BitLit lit)
1951                           || isSuitableFloatingPointLit lit
1952 isOperand _             = False
1953
1954 -- if we want a floating-point literal as an operand, we can
1955 -- use it directly from memory.  However, if the literal is
1956 -- zero, we're better off generating it into a register using
1957 -- xor.
1958 isSuitableFloatingPointLit (CmmFloat f _) = f /= 0.0
1959 isSuitableFloatingPointLit _ = False
1960
1961 getRegOrMem :: CmmExpr -> NatM (Operand, InstrBlock)
1962 getRegOrMem (CmmLoad mem pk)
1963   | IF_ARCH_i386(not (isFloatingRep pk) && pk /= I64, True) = do
1964     Amode src mem_code <- getAmode mem
1965     return (OpAddr src, mem_code)
1966 getRegOrMem e = do
1967     (reg, code) <- getNonClobberedReg e
1968     return (OpReg reg, code)
1969
1970 #if x86_64_TARGET_ARCH
1971 is64BitLit (CmmInt i I64) = i > 0x7fffffff || i < -0x80000000
1972    -- assume that labels are in the range 0-2^31-1: this assumes the
1973    -- small memory model (see gcc docs, -mcmodel=small).
1974 #endif
1975 is64BitLit x = False
1976 #endif
1977
1978 -- -----------------------------------------------------------------------------
1979 --  The 'CondCode' type:  Condition codes passed up the tree.
1980
1981 data CondCode = CondCode Bool Cond InstrBlock
1982
1983 -- Set up a condition code for a conditional branch.
1984
1985 getCondCode :: CmmExpr -> NatM CondCode
1986
1987 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1988
1989 #if alpha_TARGET_ARCH
1990 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1991 #endif /* alpha_TARGET_ARCH */
1992
1993 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1994
1995 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH || sparc_TARGET_ARCH
1996 -- yes, they really do seem to want exactly the same!
1997
1998 getCondCode (CmmMachOp mop [x, y])
1999   = ASSERT (cmmExprRep x /= I8) -- tmp, not set up to handle 8-bit comparisons
2000     case mop of
2001       MO_Eq F32 -> condFltCode EQQ x y
2002       MO_Ne F32 -> condFltCode NE  x y
2003
2004       MO_S_Gt F32 -> condFltCode GTT x y
2005       MO_S_Ge F32 -> condFltCode GE  x y
2006       MO_S_Lt F32 -> condFltCode LTT x y
2007       MO_S_Le F32 -> condFltCode LE  x y
2008
2009       MO_Eq F64 -> condFltCode EQQ x y
2010       MO_Ne F64 -> condFltCode NE  x y
2011
2012       MO_S_Gt F64 -> condFltCode GTT x y
2013       MO_S_Ge F64 -> condFltCode GE  x y
2014       MO_S_Lt F64 -> condFltCode LTT x y
2015       MO_S_Le F64 -> condFltCode LE  x y
2016
2017       MO_Eq rep -> condIntCode EQQ  x y
2018       MO_Ne rep -> condIntCode NE   x y
2019
2020       MO_S_Gt rep -> condIntCode GTT  x y
2021       MO_S_Ge rep -> condIntCode GE   x y
2022       MO_S_Lt rep -> condIntCode LTT  x y
2023       MO_S_Le rep -> condIntCode LE   x y
2024
2025       MO_U_Gt rep -> condIntCode GU   x y
2026       MO_U_Ge rep -> condIntCode GEU  x y
2027       MO_U_Lt rep -> condIntCode LU   x y
2028       MO_U_Le rep -> condIntCode LEU  x y
2029
2030       other -> pprPanic "getCondCode(x86,sparc)" (pprMachOp mop)
2031
2032 getCondCode other =  pprPanic "getCondCode(2)(x86,sparc)" (ppr other)
2033
2034 #elif powerpc_TARGET_ARCH
2035
2036 -- almost the same as everywhere else - but we need to
2037 -- extend small integers to 32 bit first
2038
2039 getCondCode (CmmMachOp mop [x, y])
2040   = case mop of
2041       MO_Eq F32 -> condFltCode EQQ x y
2042       MO_Ne F32 -> condFltCode NE  x y
2043
2044       MO_S_Gt F32 -> condFltCode GTT x y
2045       MO_S_Ge F32 -> condFltCode GE  x y
2046       MO_S_Lt F32 -> condFltCode LTT x y
2047       MO_S_Le F32 -> condFltCode LE  x y
2048
2049       MO_Eq F64 -> condFltCode EQQ x y
2050       MO_Ne F64 -> condFltCode NE  x y
2051
2052       MO_S_Gt F64 -> condFltCode GTT x y
2053       MO_S_Ge F64 -> condFltCode GE  x y
2054       MO_S_Lt F64 -> condFltCode LTT x y
2055       MO_S_Le F64 -> condFltCode LE  x y
2056
2057       MO_Eq rep -> condIntCode EQQ  (extendUExpr rep x) (extendUExpr rep y)
2058       MO_Ne rep -> condIntCode NE   (extendUExpr rep x) (extendUExpr rep y)
2059
2060       MO_S_Gt rep -> condIntCode GTT  (extendSExpr rep x) (extendSExpr rep y)
2061       MO_S_Ge rep -> condIntCode GE   (extendSExpr rep x) (extendSExpr rep y)
2062       MO_S_Lt rep -> condIntCode LTT  (extendSExpr rep x) (extendSExpr rep y)
2063       MO_S_Le rep -> condIntCode LE   (extendSExpr rep x) (extendSExpr rep y)
2064
2065       MO_U_Gt rep -> condIntCode GU   (extendUExpr rep x) (extendUExpr rep y)
2066       MO_U_Ge rep -> condIntCode GEU  (extendUExpr rep x) (extendUExpr rep y)
2067       MO_U_Lt rep -> condIntCode LU   (extendUExpr rep x) (extendUExpr rep y)
2068       MO_U_Le rep -> condIntCode LEU  (extendUExpr rep x) (extendUExpr rep y)
2069
2070       other -> pprPanic "getCondCode(powerpc)" (pprMachOp mop)
2071
2072 getCondCode other =  panic "getCondCode(2)(powerpc)"
2073
2074
2075 #endif
2076
2077
2078 -- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
2079 -- passed back up the tree.
2080
2081 condIntCode, condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode
2082
2083 #if alpha_TARGET_ARCH
2084 condIntCode = panic "MachCode.condIntCode: not on Alphas"
2085 condFltCode = panic "MachCode.condFltCode: not on Alphas"
2086 #endif /* alpha_TARGET_ARCH */
2087
2088 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2089 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
2090
2091 -- memory vs immediate
2092 condIntCode cond (CmmLoad x pk) (CmmLit lit) | not (is64BitLit lit) = do
2093     Amode x_addr x_code <- getAmode x
2094     let
2095         imm  = litToImm lit
2096         code = x_code `snocOL`
2097                   CMP pk (OpImm imm) (OpAddr x_addr)
2098     --
2099     return (CondCode False cond code)
2100
2101 -- anything vs zero
2102 condIntCode cond x (CmmLit (CmmInt 0 pk)) = do
2103     (x_reg, x_code) <- getSomeReg x
2104     let
2105         code = x_code `snocOL`
2106                   TEST pk (OpReg x_reg) (OpReg x_reg)
2107     --
2108     return (CondCode False cond code)
2109
2110 -- anything vs operand
2111 condIntCode cond x y | isOperand y = do
2112     (x_reg, x_code) <- getNonClobberedReg x
2113     (y_op,  y_code) <- getOperand y    
2114     let
2115         code = x_code `appOL` y_code `snocOL`
2116                   CMP (cmmExprRep x) y_op (OpReg x_reg)
2117     -- in
2118     return (CondCode False cond code)
2119
2120 -- anything vs anything
2121 condIntCode cond x y = do
2122   (y_reg, y_code) <- getNonClobberedReg y
2123   (x_op, x_code) <- getRegOrMem x
2124   let
2125         code = y_code `appOL`
2126                x_code `snocOL`
2127                   CMP (cmmExprRep x) (OpReg y_reg) x_op
2128   -- in
2129   return (CondCode False cond code)
2130 #endif
2131
2132 #if i386_TARGET_ARCH
2133 condFltCode cond x y 
2134   = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT])) do
2135   (x_reg, x_code) <- getNonClobberedReg x
2136   (y_reg, y_code) <- getSomeReg y
2137   let
2138         code = x_code `appOL` y_code `snocOL`
2139                 GCMP cond x_reg y_reg
2140   -- The GCMP insn does the test and sets the zero flag if comparable
2141   -- and true.  Hence we always supply EQQ as the condition to test.
2142   return (CondCode True EQQ code)
2143 #endif /* i386_TARGET_ARCH */
2144
2145 #if x86_64_TARGET_ARCH
2146 -- in the SSE2 comparison ops (ucomiss, ucomisd) the left arg may be
2147 -- an operand, but the right must be a reg.  We can probably do better
2148 -- than this general case...
2149 condFltCode cond x y = do
2150   (x_reg, x_code) <- getNonClobberedReg x
2151   (y_op, y_code) <- getOperand y
2152   let
2153         code = x_code `appOL`
2154                y_code `snocOL`
2155                   CMP (cmmExprRep x) y_op (OpReg x_reg)
2156         -- NB(1): we need to use the unsigned comparison operators on the
2157         -- result of this comparison.
2158   -- in
2159   return (CondCode True (condToUnsigned cond) code)
2160 #endif
2161
2162 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2163
2164 #if sparc_TARGET_ARCH
2165
2166 condIntCode cond x (CmmLit (CmmInt y rep))
2167   | fits13Bits y
2168   = do
2169        (src1, code) <- getSomeReg x
2170        let
2171            src2 = ImmInt (fromInteger y)
2172            code' = code `snocOL` SUB False True src1 (RIImm src2) g0
2173        return (CondCode False cond code')
2174
2175 condIntCode cond x y = do
2176     (src1, code1) <- getSomeReg x
2177     (src2, code2) <- getSomeReg y
2178     let
2179         code__2 = code1 `appOL` code2 `snocOL`
2180                   SUB False True src1 (RIReg src2) g0
2181     return (CondCode False cond code__2)
2182
2183 -----------
2184 condFltCode cond x y = do
2185     (src1, code1) <- getSomeReg x
2186     (src2, code2) <- getSomeReg y
2187     tmp <- getNewRegNat F64
2188     let
2189         promote x = FxTOy F32 F64 x tmp
2190
2191         pk1   = cmmExprRep x
2192         pk2   = cmmExprRep y
2193
2194         code__2 =
2195                 if pk1 == pk2 then
2196                     code1 `appOL` code2 `snocOL`
2197                     FCMP True pk1 src1 src2
2198                 else if pk1 == F32 then
2199                     code1 `snocOL` promote src1 `appOL` code2 `snocOL`
2200                     FCMP True F64 tmp src2
2201                 else
2202                     code1 `appOL` code2 `snocOL` promote src2 `snocOL`
2203                     FCMP True F64 src1 tmp
2204     return (CondCode True cond code__2)
2205
2206 #endif /* sparc_TARGET_ARCH */
2207
2208 #if powerpc_TARGET_ARCH
2209 --  ###FIXME: I16 and I8!
2210 condIntCode cond x (CmmLit (CmmInt y rep))
2211   | Just src2 <- makeImmediate rep (not $ condUnsigned cond) y
2212   = do
2213         (src1, code) <- getSomeReg x
2214         let
2215             code' = code `snocOL` 
2216                 (if condUnsigned cond then CMPL else CMP) I32 src1 (RIImm src2)
2217         return (CondCode False cond code')
2218
2219 condIntCode cond x y = do
2220     (src1, code1) <- getSomeReg x
2221     (src2, code2) <- getSomeReg y
2222     let
2223         code' = code1 `appOL` code2 `snocOL`
2224                   (if condUnsigned cond then CMPL else CMP) I32 src1 (RIReg src2)
2225     return (CondCode False cond code')
2226
2227 condFltCode cond x y = do
2228     (src1, code1) <- getSomeReg x
2229     (src2, code2) <- getSomeReg y
2230     let
2231         code'  = code1 `appOL` code2 `snocOL` FCMP src1 src2
2232         code'' = case cond of -- twiddle CR to handle unordered case
2233                     GE -> code' `snocOL` CRNOR ltbit eqbit gtbit
2234                     LE -> code' `snocOL` CRNOR gtbit eqbit ltbit
2235                     _ -> code'
2236                  where
2237                     ltbit = 0 ; eqbit = 2 ; gtbit = 1
2238     return (CondCode True cond code'')
2239
2240 #endif /* powerpc_TARGET_ARCH */
2241
2242 -- -----------------------------------------------------------------------------
2243 -- Generating assignments
2244
2245 -- Assignments are really at the heart of the whole code generation
2246 -- business.  Almost all top-level nodes of any real importance are
2247 -- assignments, which correspond to loads, stores, or register
2248 -- transfers.  If we're really lucky, some of the register transfers
2249 -- will go away, because we can use the destination register to
2250 -- complete the code generation for the right hand side.  This only
2251 -- fails when the right hand side is forced into a fixed register
2252 -- (e.g. the result of a call).
2253
2254 assignMem_IntCode :: MachRep -> CmmExpr -> CmmExpr -> NatM InstrBlock
2255 assignReg_IntCode :: MachRep -> CmmReg  -> CmmExpr -> NatM InstrBlock
2256
2257 assignMem_FltCode :: MachRep -> CmmExpr -> CmmExpr -> NatM InstrBlock
2258 assignReg_FltCode :: MachRep -> CmmReg  -> CmmExpr -> NatM InstrBlock
2259
2260 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2261
2262 #if alpha_TARGET_ARCH
2263
2264 assignIntCode pk (CmmLoad dst _) src
2265   = getNewRegNat IntRep             `thenNat` \ tmp ->
2266     getAmode dst                    `thenNat` \ amode ->
2267     getRegister src                 `thenNat` \ register ->
2268     let
2269         code1   = amodeCode amode []
2270         dst__2  = amodeAddr amode
2271         code2   = registerCode register tmp []
2272         src__2  = registerName register tmp
2273         sz      = primRepToSize pk
2274         code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2275     in
2276     return code__2
2277
2278 assignIntCode pk dst src
2279   = getRegister dst                         `thenNat` \ register1 ->
2280     getRegister src                         `thenNat` \ register2 ->
2281     let
2282         dst__2  = registerName register1 zeroh
2283         code    = registerCode register2 dst__2
2284         src__2  = registerName register2 dst__2
2285         code__2 = if isFixed register2
2286                   then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
2287                   else code
2288     in
2289     return code__2
2290
2291 #endif /* alpha_TARGET_ARCH */
2292
2293 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2294
2295 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
2296
2297 -- integer assignment to memory
2298 assignMem_IntCode pk addr src = do
2299     Amode addr code_addr <- getAmode addr
2300     (code_src, op_src)   <- get_op_RI src
2301     let
2302         code = code_src `appOL`
2303                code_addr `snocOL`
2304                   MOV pk op_src (OpAddr addr)
2305         -- NOTE: op_src is stable, so it will still be valid
2306         -- after code_addr.  This may involve the introduction 
2307         -- of an extra MOV to a temporary register, but we hope
2308         -- the register allocator will get rid of it.
2309     --
2310     return code
2311   where
2312     get_op_RI :: CmmExpr -> NatM (InstrBlock,Operand)   -- code, operator
2313     get_op_RI (CmmLit lit) | not (is64BitLit lit)
2314       = return (nilOL, OpImm (litToImm lit))
2315     get_op_RI op
2316       = do (reg,code) <- getNonClobberedReg op
2317            return (code, OpReg reg)
2318
2319
2320 -- Assign; dst is a reg, rhs is mem
2321 assignReg_IntCode pk reg (CmmLoad src _) = do
2322   load_code <- intLoadCode (MOV pk) src
2323   return (load_code (getRegisterReg reg))
2324
2325 -- dst is a reg, but src could be anything
2326 assignReg_IntCode pk reg src = do
2327   code <- getAnyReg src
2328   return (code (getRegisterReg reg))
2329
2330 #endif /* i386_TARGET_ARCH */
2331
2332 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2333
2334 #if sparc_TARGET_ARCH
2335
2336 assignMem_IntCode pk addr src = do
2337     (srcReg, code) <- getSomeReg src
2338     Amode dstAddr addr_code <- getAmode addr
2339     return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
2340
2341 assignReg_IntCode pk reg src = do
2342     r <- getRegister src
2343     return $ case r of
2344         Any _ code         -> code dst
2345         Fixed _ freg fcode -> fcode `snocOL` OR False g0 (RIReg dst) freg
2346     where
2347       dst = getRegisterReg reg
2348
2349
2350 #endif /* sparc_TARGET_ARCH */
2351
2352 #if powerpc_TARGET_ARCH
2353
2354 assignMem_IntCode pk addr src = do
2355     (srcReg, code) <- getSomeReg src
2356     Amode dstAddr addr_code <- getAmode addr
2357     return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
2358
2359 -- dst is a reg, but src could be anything
2360 assignReg_IntCode pk reg src
2361     = do
2362         r <- getRegister src
2363         return $ case r of
2364             Any _ code         -> code dst
2365             Fixed _ freg fcode -> fcode `snocOL` MR dst freg
2366     where
2367         dst = getRegisterReg reg
2368
2369 #endif /* powerpc_TARGET_ARCH */
2370
2371
2372 -- -----------------------------------------------------------------------------
2373 -- Floating-point assignments
2374
2375 #if alpha_TARGET_ARCH
2376
2377 assignFltCode pk (CmmLoad dst _) src
2378   = getNewRegNat pk                 `thenNat` \ tmp ->
2379     getAmode dst                    `thenNat` \ amode ->
2380     getRegister src                         `thenNat` \ register ->
2381     let
2382         code1   = amodeCode amode []
2383         dst__2  = amodeAddr amode
2384         code2   = registerCode register tmp []
2385         src__2  = registerName register tmp
2386         sz      = primRepToSize pk
2387         code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
2388     in
2389     return code__2
2390
2391 assignFltCode pk dst src
2392   = getRegister dst                         `thenNat` \ register1 ->
2393     getRegister src                         `thenNat` \ register2 ->
2394     let
2395         dst__2  = registerName register1 zeroh
2396         code    = registerCode register2 dst__2
2397         src__2  = registerName register2 dst__2
2398         code__2 = if isFixed register2
2399                   then code . mkSeqInstr (FMOV src__2 dst__2)
2400                   else code
2401     in
2402     return code__2
2403
2404 #endif /* alpha_TARGET_ARCH */
2405
2406 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2407
2408 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
2409
2410 -- Floating point assignment to memory
2411 assignMem_FltCode pk addr src = do
2412   (src_reg, src_code) <- getNonClobberedReg src
2413   Amode addr addr_code <- getAmode addr
2414   let
2415         code = src_code `appOL`
2416                addr_code `snocOL`
2417                 IF_ARCH_i386(GST pk src_reg addr,
2418                              MOV pk (OpReg src_reg) (OpAddr addr))
2419   return code
2420
2421 -- Floating point assignment to a register/temporary
2422 assignReg_FltCode pk reg src = do
2423   src_code <- getAnyReg src
2424   return (src_code (getRegisterReg reg))
2425
2426 #endif /* i386_TARGET_ARCH */
2427
2428 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2429
2430 #if sparc_TARGET_ARCH
2431
2432 -- Floating point assignment to memory
2433 assignMem_FltCode pk addr src = do
2434     Amode dst__2 code1 <- getAmode addr
2435     (src__2, code2) <- getSomeReg src
2436     tmp1 <- getNewRegNat pk
2437     let
2438         pk__2   = cmmExprRep src
2439         code__2 = code1 `appOL` code2 `appOL`
2440             if   pk == pk__2 
2441             then unitOL (ST pk src__2 dst__2)
2442             else toOL [FxTOy pk__2 pk src__2 tmp1, ST pk tmp1 dst__2]
2443     return code__2
2444
2445 -- Floating point assignment to a register/temporary
2446 -- ToDo: Verify correctness
2447 assignReg_FltCode pk reg src = do
2448     r <- getRegister src
2449     v1 <- getNewRegNat pk
2450     return $ case r of
2451         Any _ code         -> code dst
2452         Fixed _ freg fcode -> fcode `snocOL` FMOV pk freg v1
2453     where
2454       dst = getRegisterReg reg
2455
2456 #endif /* sparc_TARGET_ARCH */
2457
2458 #if powerpc_TARGET_ARCH
2459
2460 -- Easy, isn't it?
2461 assignMem_FltCode = assignMem_IntCode
2462 assignReg_FltCode = assignReg_IntCode
2463
2464 #endif /* powerpc_TARGET_ARCH */
2465
2466
2467 -- -----------------------------------------------------------------------------
2468 -- Generating an non-local jump
2469
2470 -- (If applicable) Do not fill the delay slots here; you will confuse the
2471 -- register allocator.
2472
2473 genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock
2474
2475 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2476
2477 #if alpha_TARGET_ARCH
2478
2479 genJump (CmmLabel lbl)
2480   | isAsmTemp lbl = returnInstr (BR target)
2481   | otherwise     = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2482   where
2483     target = ImmCLbl lbl
2484
2485 genJump tree
2486   = getRegister tree                `thenNat` \ register ->
2487     getNewRegNat PtrRep             `thenNat` \ tmp ->
2488     let
2489         dst    = registerName register pv
2490         code   = registerCode register pv
2491         target = registerName register pv
2492     in
2493     if isFixed register then
2494         returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2495     else
2496     return (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2497
2498 #endif /* alpha_TARGET_ARCH */
2499
2500 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2501
2502 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
2503
2504 genJump (CmmLoad mem pk) = do
2505   Amode target code <- getAmode mem
2506   return (code `snocOL` JMP (OpAddr target))
2507
2508 genJump (CmmLit lit) = do
2509   return (unitOL (JMP (OpImm (litToImm lit))))
2510
2511 genJump expr = do
2512   (reg,code) <- getSomeReg expr
2513   return (code `snocOL` JMP (OpReg reg))
2514
2515 #endif /* i386_TARGET_ARCH */
2516
2517 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2518
2519 #if sparc_TARGET_ARCH
2520
2521 genJump (CmmLit (CmmLabel lbl))
2522   = return (toOL [CALL (Left target) 0 True, NOP])
2523   where
2524     target = ImmCLbl lbl
2525
2526 genJump tree
2527   = do
2528         (target, code) <- getSomeReg tree
2529         return (code `snocOL` JMP (AddrRegReg target g0)  `snocOL` NOP)
2530
2531 #endif /* sparc_TARGET_ARCH */
2532
2533 #if powerpc_TARGET_ARCH
2534 genJump (CmmLit (CmmLabel lbl))
2535   = return (unitOL $ JMP lbl)
2536
2537 genJump tree
2538   = do
2539         (target,code) <- getSomeReg tree
2540         return (code `snocOL` MTCTR target `snocOL` BCTR [])
2541 #endif /* powerpc_TARGET_ARCH */
2542
2543
2544 -- -----------------------------------------------------------------------------
2545 --  Unconditional branches
2546
2547 genBranch :: BlockId -> NatM InstrBlock
2548
2549 #if alpha_TARGET_ARCH
2550 genBranch id = return (unitOL (BR id))
2551 #endif
2552
2553 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
2554 genBranch id = return (unitOL (JXX ALWAYS id))
2555 #endif
2556
2557 #if sparc_TARGET_ARCH
2558 genBranch (BlockId id) = return (toOL [BI ALWAYS False (ImmCLbl (mkAsmTempLabel id)), NOP])
2559 #endif
2560
2561 #if powerpc_TARGET_ARCH
2562 genBranch id = return (unitOL (BCC ALWAYS id))
2563 #endif
2564
2565
2566 -- -----------------------------------------------------------------------------
2567 --  Conditional jumps
2568
2569 {-
2570 Conditional jumps are always to local labels, so we can use branch
2571 instructions.  We peek at the arguments to decide what kind of
2572 comparison to do.
2573
2574 ALPHA: For comparisons with 0, we're laughing, because we can just do
2575 the desired conditional branch.
2576
2577 I386: First, we have to ensure that the condition
2578 codes are set according to the supplied comparison operation.
2579
2580 SPARC: First, we have to ensure that the condition codes are set
2581 according to the supplied comparison operation.  We generate slightly
2582 different code for floating point comparisons, because a floating
2583 point operation cannot directly precede a @BF@.  We assume the worst
2584 and fill that slot with a @NOP@.
2585
2586 SPARC: Do not fill the delay slots here; you will confuse the register
2587 allocator.
2588 -}
2589
2590
2591 genCondJump
2592     :: BlockId      -- the branch target
2593     -> CmmExpr      -- the condition on which to branch
2594     -> NatM InstrBlock
2595
2596 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2597
2598 #if alpha_TARGET_ARCH
2599
2600 genCondJump id (StPrim op [x, StInt 0])
2601   = getRegister x                           `thenNat` \ register ->
2602     getNewRegNat (registerRep register)
2603                                     `thenNat` \ tmp ->
2604     let
2605         code   = registerCode register tmp
2606         value  = registerName register tmp
2607         pk     = registerRep register
2608         target = ImmCLbl lbl
2609     in
2610     returnSeq code [BI (cmpOp op) value target]
2611   where
2612     cmpOp CharGtOp = GTT
2613     cmpOp CharGeOp = GE
2614     cmpOp CharEqOp = EQQ
2615     cmpOp CharNeOp = NE
2616     cmpOp CharLtOp = LTT
2617     cmpOp CharLeOp = LE
2618     cmpOp IntGtOp = GTT
2619     cmpOp IntGeOp = GE
2620     cmpOp IntEqOp = EQQ
2621     cmpOp IntNeOp = NE
2622     cmpOp IntLtOp = LTT
2623     cmpOp IntLeOp = LE
2624     cmpOp WordGtOp = NE
2625     cmpOp WordGeOp = ALWAYS
2626     cmpOp WordEqOp = EQQ
2627     cmpOp WordNeOp = NE
2628     cmpOp WordLtOp = NEVER
2629     cmpOp WordLeOp = EQQ
2630     cmpOp AddrGtOp = NE
2631     cmpOp AddrGeOp = ALWAYS
2632     cmpOp AddrEqOp = EQQ
2633     cmpOp AddrNeOp = NE
2634     cmpOp AddrLtOp = NEVER
2635     cmpOp AddrLeOp = EQQ
2636
2637 genCondJump lbl (StPrim op [x, StDouble 0.0])
2638   = getRegister x                           `thenNat` \ register ->
2639     getNewRegNat (registerRep register)
2640                                     `thenNat` \ tmp ->
2641     let
2642         code   = registerCode register tmp
2643         value  = registerName register tmp
2644         pk     = registerRep register
2645         target = ImmCLbl lbl
2646     in
2647     return (code . mkSeqInstr (BF (cmpOp op) value target))
2648   where
2649     cmpOp FloatGtOp = GTT
2650     cmpOp FloatGeOp = GE
2651     cmpOp FloatEqOp = EQQ
2652     cmpOp FloatNeOp = NE
2653     cmpOp FloatLtOp = LTT
2654     cmpOp FloatLeOp = LE
2655     cmpOp DoubleGtOp = GTT
2656     cmpOp DoubleGeOp = GE
2657     cmpOp DoubleEqOp = EQQ
2658     cmpOp DoubleNeOp = NE
2659     cmpOp DoubleLtOp = LTT
2660     cmpOp DoubleLeOp = LE
2661
2662 genCondJump lbl (StPrim op [x, y])
2663   | fltCmpOp op
2664   = trivialFCode pr instr x y       `thenNat` \ register ->
2665     getNewRegNat F64                `thenNat` \ tmp ->
2666     let
2667         code   = registerCode register tmp
2668         result = registerName register tmp
2669         target = ImmCLbl lbl
2670     in
2671     return (code . mkSeqInstr (BF cond result target))
2672   where
2673     pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2674
2675     fltCmpOp op = case op of
2676         FloatGtOp -> True
2677         FloatGeOp -> True
2678         FloatEqOp -> True
2679         FloatNeOp -> True
2680         FloatLtOp -> True
2681         FloatLeOp -> True
2682         DoubleGtOp -> True
2683         DoubleGeOp -> True
2684         DoubleEqOp -> True
2685         DoubleNeOp -> True
2686         DoubleLtOp -> True
2687         DoubleLeOp -> True
2688         _ -> False
2689     (instr, cond) = case op of
2690         FloatGtOp -> (FCMP TF LE, EQQ)
2691         FloatGeOp -> (FCMP TF LTT, EQQ)
2692         FloatEqOp -> (FCMP TF EQQ, NE)
2693         FloatNeOp -> (FCMP TF EQQ, EQQ)
2694         FloatLtOp -> (FCMP TF LTT, NE)
2695         FloatLeOp -> (FCMP TF LE, NE)
2696         DoubleGtOp -> (FCMP TF LE, EQQ)
2697         DoubleGeOp -> (FCMP TF LTT, EQQ)
2698         DoubleEqOp -> (FCMP TF EQQ, NE)
2699         DoubleNeOp -> (FCMP TF EQQ, EQQ)
2700         DoubleLtOp -> (FCMP TF LTT, NE)
2701         DoubleLeOp -> (FCMP TF LE, NE)
2702
2703 genCondJump lbl (StPrim op [x, y])
2704   = trivialCode instr x y           `thenNat` \ register ->
2705     getNewRegNat IntRep             `thenNat` \ tmp ->
2706     let
2707         code   = registerCode register tmp
2708         result = registerName register tmp
2709         target = ImmCLbl lbl
2710     in
2711     return (code . mkSeqInstr (BI cond result target))
2712   where
2713     (instr, cond) = case op of
2714         CharGtOp -> (CMP LE, EQQ)
2715         CharGeOp -> (CMP LTT, EQQ)
2716         CharEqOp -> (CMP EQQ, NE)
2717         CharNeOp -> (CMP EQQ, EQQ)
2718         CharLtOp -> (CMP LTT, NE)
2719         CharLeOp -> (CMP LE, NE)
2720         IntGtOp -> (CMP LE, EQQ)
2721         IntGeOp -> (CMP LTT, EQQ)
2722         IntEqOp -> (CMP EQQ, NE)
2723         IntNeOp -> (CMP EQQ, EQQ)
2724         IntLtOp -> (CMP LTT, NE)
2725         IntLeOp -> (CMP LE, NE)
2726         WordGtOp -> (CMP ULE, EQQ)
2727         WordGeOp -> (CMP ULT, EQQ)
2728         WordEqOp -> (CMP EQQ, NE)
2729         WordNeOp -> (CMP EQQ, EQQ)
2730         WordLtOp -> (CMP ULT, NE)
2731         WordLeOp -> (CMP ULE, NE)
2732         AddrGtOp -> (CMP ULE, EQQ)
2733         AddrGeOp -> (CMP ULT, EQQ)
2734         AddrEqOp -> (CMP EQQ, NE)
2735         AddrNeOp -> (CMP EQQ, EQQ)
2736         AddrLtOp -> (CMP ULT, NE)
2737         AddrLeOp -> (CMP ULE, NE)
2738
2739 #endif /* alpha_TARGET_ARCH */
2740
2741 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2742
2743 #if i386_TARGET_ARCH
2744
2745 genCondJump id bool = do
2746   CondCode _ cond code <- getCondCode bool
2747   return (code `snocOL` JXX cond id)
2748
2749 #endif
2750
2751 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2752
2753 #if x86_64_TARGET_ARCH
2754
2755 genCondJump id bool = do
2756   CondCode is_float cond cond_code <- getCondCode bool
2757   if not is_float
2758     then
2759         return (cond_code `snocOL` JXX cond id)
2760     else do
2761         lbl <- getBlockIdNat
2762
2763         -- see comment with condFltReg
2764         let code = case cond of
2765                         NE  -> or_unordered
2766                         GU  -> plain_test
2767                         GEU -> plain_test
2768                         _   -> and_ordered
2769
2770             plain_test = unitOL (
2771                   JXX cond id
2772                 )
2773             or_unordered = toOL [
2774                   JXX cond id,
2775                   JXX PARITY id
2776                 ]
2777             and_ordered = toOL [
2778                   JXX PARITY lbl,
2779                   JXX cond id,
2780                   JXX ALWAYS lbl,
2781                   NEWBLOCK lbl
2782                 ]
2783         return (cond_code `appOL` code)
2784
2785 #endif
2786
2787 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2788
2789 #if sparc_TARGET_ARCH
2790
2791 genCondJump (BlockId id) bool = do
2792   CondCode is_float cond code <- getCondCode bool
2793   return (
2794        code `appOL` 
2795        toOL (
2796          if   is_float
2797          then [NOP, BF cond False (ImmCLbl (mkAsmTempLabel id)), NOP]
2798          else [BI cond False (ImmCLbl (mkAsmTempLabel id)), NOP]
2799        )
2800     )
2801
2802 #endif /* sparc_TARGET_ARCH */
2803
2804
2805 #if powerpc_TARGET_ARCH
2806
2807 genCondJump id bool = do
2808   CondCode is_float cond code <- getCondCode bool
2809   return (code `snocOL` BCC cond id)
2810
2811 #endif /* powerpc_TARGET_ARCH */
2812
2813
2814 -- -----------------------------------------------------------------------------
2815 --  Generating C calls
2816
2817 -- Now the biggest nightmare---calls.  Most of the nastiness is buried in
2818 -- @get_arg@, which moves the arguments to the correct registers/stack
2819 -- locations.  Apart from that, the code is easy.
2820 -- 
2821 -- (If applicable) Do not fill the delay slots here; you will confuse the
2822 -- register allocator.
2823
2824 genCCall
2825     :: CmmCallTarget            -- function to call
2826     -> [(CmmReg,MachHint)]      -- where to put the result
2827     -> [(CmmExpr,MachHint)]     -- arguments (of mixed type)
2828     -> Maybe [GlobalReg]        -- volatile regs to save
2829     -> NatM InstrBlock
2830
2831 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2832
2833 #if alpha_TARGET_ARCH
2834
2835 ccallResultRegs = 
2836
2837 genCCall fn cconv result_regs args
2838   = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2839                           `thenNat` \ ((unused,_), argCode) ->
2840     let
2841         nRegs = length allArgRegs - length unused
2842         code = asmSeqThen (map ($ []) argCode)
2843     in
2844         returnSeq code [
2845             LDA pv (AddrImm (ImmLab (ptext fn))),
2846             JSR ra (AddrReg pv) nRegs,
2847             LDGP gp (AddrReg ra)]
2848   where
2849     ------------------------
2850     {-  Try to get a value into a specific register (or registers) for
2851         a call.  The first 6 arguments go into the appropriate
2852         argument register (separate registers for integer and floating
2853         point arguments, but used in lock-step), and the remaining
2854         arguments are dumped to the stack, beginning at 0(sp).  Our
2855         first argument is a pair of the list of remaining argument
2856         registers to be assigned for this call and the next stack
2857         offset to use for overflowing arguments.  This way,
2858         @get_Arg@ can be applied to all of a call's arguments using
2859         @mapAccumLNat@.
2860     -}
2861     get_arg
2862         :: ([(Reg,Reg)], Int)   -- Argument registers and stack offset (accumulator)
2863         -> StixTree             -- Current argument
2864         -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2865
2866     -- We have to use up all of our argument registers first...
2867
2868     get_arg ((iDst,fDst):dsts, offset) arg
2869       = getRegister arg                     `thenNat` \ register ->
2870         let
2871             reg  = if isFloatingRep pk then fDst else iDst
2872             code = registerCode register reg
2873             src  = registerName register reg
2874             pk   = registerRep register
2875         in
2876         return (
2877             if isFloatingRep pk then
2878                 ((dsts, offset), if isFixed register then
2879                     code . mkSeqInstr (FMOV src fDst)
2880                     else code)
2881             else
2882                 ((dsts, offset), if isFixed register then
2883                     code . mkSeqInstr (OR src (RIReg src) iDst)
2884                     else code))
2885
2886     -- Once we have run out of argument registers, we move to the
2887     -- stack...
2888
2889     get_arg ([], offset) arg
2890       = getRegister arg                 `thenNat` \ register ->
2891         getNewRegNat (registerRep register)
2892                                         `thenNat` \ tmp ->
2893         let
2894             code = registerCode register tmp
2895             src  = registerName register tmp
2896             pk   = registerRep register
2897             sz   = primRepToSize pk
2898         in
2899         return (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2900
2901 #endif /* alpha_TARGET_ARCH */
2902
2903 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2904
2905 #if i386_TARGET_ARCH
2906
2907 -- we only cope with a single result for foreign calls
2908 genCCall (CmmPrim op) [(r,_)] args vols = do
2909   case op of
2910         MO_F32_Sqrt -> actuallyInlineFloatOp F32  (GSQRT F32) args
2911         MO_F64_Sqrt -> actuallyInlineFloatOp F64 (GSQRT F64) args
2912         
2913         MO_F32_Sin  -> actuallyInlineFloatOp F32  (GSIN F32) args
2914         MO_F64_Sin  -> actuallyInlineFloatOp F64 (GSIN F64) args
2915         
2916         MO_F32_Cos  -> actuallyInlineFloatOp F32  (GCOS F32) args
2917         MO_F64_Cos  -> actuallyInlineFloatOp F64 (GCOS F64) args
2918         
2919         MO_F32_Tan  -> actuallyInlineFloatOp F32  (GTAN F32) args
2920         MO_F64_Tan  -> actuallyInlineFloatOp F64 (GTAN F64) args
2921         
2922         other_op    -> outOfLineFloatOp op r args vols
2923  where
2924   actuallyInlineFloatOp rep instr [(x,_)]
2925         = do res <- trivialUFCode rep instr x
2926              any <- anyReg res
2927              return (any (getRegisterReg r))
2928
2929 genCCall target dest_regs args vols = do
2930     sizes_n_codes <- mapM push_arg (reverse args)
2931     delta <- getDeltaNat
2932     let 
2933         (sizes, push_codes) = unzip sizes_n_codes
2934         tot_arg_size        = sum sizes
2935     -- in
2936     -- deal with static vs dynamic call targets
2937     (callinsns,cconv) <-
2938       case target of
2939         -- CmmPrim -> ...
2940         CmmForeignCall (CmmLit (CmmLabel lbl)) conv
2941            -> -- ToDo: stdcall arg sizes
2942               return (unitOL (CALL (Left fn_imm) []), conv)
2943            where fn_imm = ImmCLbl lbl
2944         CmmForeignCall expr conv
2945            -> do (dyn_c, dyn_r, dyn_rep) <- get_op expr
2946                  ASSERT(dyn_rep == I32)
2947                   return (dyn_c `snocOL` CALL (Right dyn_r) [], conv)
2948
2949     let push_code = concatOL push_codes
2950         call = callinsns `appOL`
2951                toOL (
2952                         -- Deallocate parameters after call for ccall;
2953                         -- but not for stdcall (callee does it)
2954                   (if cconv == StdCallConv || tot_arg_size==0 then [] else 
2955                    [ADD I32 (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2956                   ++
2957                   [DELTA (delta + tot_arg_size)]
2958                )
2959     -- in
2960     setDeltaNat (delta + tot_arg_size)
2961
2962     let
2963         -- assign the results, if necessary
2964         assign_code []     = nilOL
2965         assign_code [(dest,_hint)] = 
2966           case rep of
2967                 I64 -> toOL [MOV I32 (OpReg eax) (OpReg r_dest),
2968                              MOV I32 (OpReg edx) (OpReg r_dest_hi)]
2969                 F32 -> unitOL (GMOV fake0 r_dest)
2970                 F64 -> unitOL (GMOV fake0 r_dest)
2971                 rep -> unitOL (MOV rep (OpReg eax) (OpReg r_dest))
2972           where 
2973                 r_dest_hi = getHiVRegFromLo r_dest
2974                 rep = cmmRegRep dest
2975                 r_dest = getRegisterReg dest
2976         assign_code many = panic "genCCall.assign_code many"
2977
2978     return (push_code `appOL` 
2979             call `appOL` 
2980             assign_code dest_regs)
2981
2982   where
2983     arg_size F64 = 8
2984     arg_size F32 = 4
2985     arg_size _   = 4
2986
2987     push_arg :: (CmmExpr,MachHint){-current argument-}
2988                     -> NatM (Int, InstrBlock)  -- argsz, code
2989
2990     push_arg (arg,_hint) -- we don't need the hints on x86
2991       | arg_rep == I64 = do
2992         ChildCode64 code r_lo <- iselExpr64 arg
2993         delta <- getDeltaNat
2994         setDeltaNat (delta - 8)
2995         let 
2996             r_hi = getHiVRegFromLo r_lo
2997         -- in
2998         return (8,     code `appOL`
2999                        toOL [PUSH I32 (OpReg r_hi), DELTA (delta - 4),
3000                              PUSH I32 (OpReg r_lo), DELTA (delta - 8),
3001                              DELTA (delta-8)]
3002             )
3003
3004       | otherwise = do
3005         (code, reg, sz) <- get_op arg
3006         delta <- getDeltaNat
3007         let size = arg_size sz
3008         setDeltaNat (delta-size)
3009         if (case sz of F64 -> True; F32 -> True; _ -> False)
3010            then return (size,
3011                         code `appOL`
3012                         toOL [SUB I32 (OpImm (ImmInt size)) (OpReg esp),
3013                               DELTA (delta-size),
3014                               GST sz reg (AddrBaseIndex (EABaseReg esp) 
3015                                                         EAIndexNone
3016                                                         (ImmInt 0))]
3017                        )
3018            else return (size,
3019                         code `snocOL`
3020                         PUSH I32 (OpReg reg) `snocOL`
3021                         DELTA (delta-size)
3022                        )
3023       where
3024          arg_rep = cmmExprRep arg
3025
3026     ------------
3027     get_op :: CmmExpr -> NatM (InstrBlock, Reg, MachRep) -- code, reg, size
3028     get_op op = do
3029         (reg,code) <- getSomeReg op
3030         return (code, reg, cmmExprRep op)
3031
3032 #endif /* i386_TARGET_ARCH */
3033
3034 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
3035
3036 outOfLineFloatOp :: CallishMachOp -> CmmReg -> [(CmmExpr,MachHint)]
3037   -> Maybe [GlobalReg] -> NatM InstrBlock
3038 outOfLineFloatOp mop res args vols
3039   | cmmRegRep res == F64
3040   = stmtToInstrs (CmmCall target [(res,FloatHint)] args vols)
3041
3042   | otherwise
3043   = do uq <- getUniqueNat
3044        let 
3045          tmp = CmmLocal (LocalReg uq F64)
3046        -- in
3047        code1 <- stmtToInstrs (CmmCall target [(tmp,FloatHint)] (map promote args) vols)
3048        code2 <- stmtToInstrs (CmmAssign res (demote (CmmReg tmp)))
3049        return (code1 `appOL` code2)
3050   where
3051         promote (x,hint) = (CmmMachOp (MO_S_Conv F32 F64) [x], hint)
3052         demote  x = CmmMachOp (MO_S_Conv F64 F32) [x]
3053
3054         target = CmmForeignCall (CmmLit lbl) CCallConv
3055         lbl = CmmLabel (mkForeignLabel fn Nothing False)
3056
3057         fn = case mop of
3058               MO_F32_Sqrt  -> FSLIT("sqrt")
3059               MO_F32_Sin   -> FSLIT("sin")
3060               MO_F32_Cos   -> FSLIT("cos")
3061               MO_F32_Tan   -> FSLIT("tan")
3062               MO_F32_Exp   -> FSLIT("exp")
3063               MO_F32_Log   -> FSLIT("log")
3064
3065               MO_F32_Asin  -> FSLIT("asin")
3066               MO_F32_Acos  -> FSLIT("acos")
3067               MO_F32_Atan  -> FSLIT("atan")
3068
3069               MO_F32_Sinh  -> FSLIT("sinh")
3070               MO_F32_Cosh  -> FSLIT("cosh")
3071               MO_F32_Tanh  -> FSLIT("tanh")
3072               MO_F32_Pwr   -> FSLIT("pow")
3073
3074               MO_F64_Sqrt  -> FSLIT("sqrt")
3075               MO_F64_Sin   -> FSLIT("sin")
3076               MO_F64_Cos   -> FSLIT("cos")
3077               MO_F64_Tan   -> FSLIT("tan")
3078               MO_F64_Exp   -> FSLIT("exp")
3079               MO_F64_Log   -> FSLIT("log")
3080
3081               MO_F64_Asin  -> FSLIT("asin")
3082               MO_F64_Acos  -> FSLIT("acos")
3083               MO_F64_Atan  -> FSLIT("atan")
3084
3085               MO_F64_Sinh  -> FSLIT("sinh")
3086               MO_F64_Cosh  -> FSLIT("cosh")
3087               MO_F64_Tanh  -> FSLIT("tanh")
3088               MO_F64_Pwr   -> FSLIT("pow")
3089
3090 #endif /* i386_TARGET_ARCH || x86_64_TARGET_ARCH */
3091
3092 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3093
3094 #if x86_64_TARGET_ARCH
3095
3096 genCCall (CmmPrim op) [(r,_)] args vols = 
3097   outOfLineFloatOp op r args vols
3098
3099 genCCall target dest_regs args vols = do
3100
3101         -- load up the register arguments
3102     (stack_args, aregs, fregs, load_args_code)
3103          <- load_args args allArgRegs allFPArgRegs nilOL
3104
3105     let
3106         fp_regs_used  = reverse (drop (length fregs) (reverse allFPArgRegs))
3107         int_regs_used = reverse (drop (length aregs) (reverse allArgRegs))
3108         arg_regs = int_regs_used ++ fp_regs_used
3109                 -- for annotating the call instruction with
3110
3111         sse_regs = length fp_regs_used
3112
3113         tot_arg_size = arg_size * length stack_args
3114
3115         -- On entry to the called function, %rsp should be aligned
3116         -- on a 16-byte boundary +8 (i.e. the first stack arg after
3117         -- the return address is 16-byte aligned).  In STG land
3118         -- %rsp is kept 16-byte aligned (see StgCRun.c), so we just
3119         -- need to make sure we push a multiple of 16-bytes of args,
3120         -- plus the return address, to get the correct alignment.
3121         -- Urg, this is hard.  We need to feed the delta back into
3122         -- the arg pushing code.
3123     (real_size, adjust_rsp) <-
3124         if tot_arg_size `rem` 16 == 0
3125             then return (tot_arg_size, nilOL)
3126             else do -- we need to adjust...
3127                 delta <- getDeltaNat
3128                 setDeltaNat (delta-8)
3129                 return (tot_arg_size+8, toOL [
3130                                 SUB I64 (OpImm (ImmInt 8)) (OpReg rsp),
3131                                 DELTA (delta-8)
3132                         ])
3133
3134         -- push the stack args, right to left
3135     push_code <- push_args (reverse stack_args) nilOL
3136     delta <- getDeltaNat
3137
3138     -- deal with static vs dynamic call targets
3139     (callinsns,cconv) <-
3140       case target of
3141         -- CmmPrim -> ...
3142         CmmForeignCall (CmmLit (CmmLabel lbl)) conv
3143            -> -- ToDo: stdcall arg sizes
3144               return (unitOL (CALL (Left fn_imm) arg_regs), conv)
3145            where fn_imm = ImmCLbl lbl
3146         CmmForeignCall expr conv
3147            -> do (dyn_r, dyn_c) <- getSomeReg expr
3148                  return (dyn_c `snocOL` CALL (Right dyn_r) arg_regs, conv)
3149
3150     let
3151         -- The x86_64 ABI requires us to set %al to the number of SSE
3152         -- registers that contain arguments, if the called routine
3153         -- is a varargs function.  We don't know whether it's a
3154         -- varargs function or not, so we have to assume it is.
3155         --
3156         -- It's not safe to omit this assignment, even if the number
3157         -- of SSE regs in use is zero.  If %al is larger than 8
3158         -- on entry to a varargs function, seg faults ensue.
3159         assign_eax n = unitOL (MOV I32 (OpImm (ImmInt n)) (OpReg eax))
3160
3161     let call = callinsns `appOL`
3162                toOL (
3163                         -- Deallocate parameters after call for ccall;
3164                         -- but not for stdcall (callee does it)
3165                   (if cconv == StdCallConv || real_size==0 then [] else 
3166                    [ADD wordRep (OpImm (ImmInt real_size)) (OpReg esp)])
3167                   ++
3168                   [DELTA (delta + real_size)]
3169                )
3170     -- in
3171     setDeltaNat (delta + real_size)
3172
3173     let
3174         -- assign the results, if necessary
3175         assign_code []     = nilOL
3176         assign_code [(dest,_hint)] = 
3177           case rep of
3178                 F32 -> unitOL (MOV rep (OpReg xmm0) (OpReg r_dest))
3179                 F64 -> unitOL (MOV rep (OpReg xmm0) (OpReg r_dest))
3180                 rep -> unitOL (MOV rep (OpReg rax) (OpReg r_dest))
3181           where 
3182                 rep = cmmRegRep dest
3183                 r_dest = getRegisterReg dest
3184         assign_code many = panic "genCCall.assign_code many"
3185
3186     return (load_args_code      `appOL` 
3187             adjust_rsp          `appOL`
3188             push_code           `appOL`
3189             assign_eax sse_regs `appOL`
3190             call                `appOL` 
3191             assign_code dest_regs)
3192
3193   where
3194     arg_size = 8 -- always, at the mo
3195
3196     load_args :: [(CmmExpr,MachHint)]
3197               -> [Reg]                  -- int regs avail for args
3198               -> [Reg]                  -- FP regs avail for args
3199               -> InstrBlock
3200               -> NatM ([(CmmExpr,MachHint)],[Reg],[Reg],InstrBlock)
3201     load_args args [] [] code     =  return (args, [], [], code)
3202         -- no more regs to use
3203     load_args [] aregs fregs code =  return ([], aregs, fregs, code)
3204         -- no more args to push
3205     load_args ((arg,hint) : rest) aregs fregs code
3206         | isFloatingRep arg_rep = 
3207         case fregs of
3208           [] -> push_this_arg
3209           (r:rs) -> do
3210              arg_code <- getAnyReg arg
3211              load_args rest aregs rs (code `appOL` arg_code r)
3212         | otherwise =
3213         case aregs of
3214           [] -> push_this_arg
3215           (r:rs) -> do
3216              arg_code <- getAnyReg arg
3217              load_args rest rs fregs (code `appOL` arg_code r)
3218         where
3219           arg_rep = cmmExprRep arg
3220
3221           push_this_arg = do
3222             (args',ars,frs,code') <- load_args rest aregs fregs code
3223             return ((arg,hint):args', ars, frs, code')
3224
3225     push_args [] code = return code
3226     push_args ((arg,hint):rest) code
3227        | isFloatingRep arg_rep = do
3228          (arg_reg, arg_code) <- getSomeReg arg
3229          delta <- getDeltaNat
3230          setDeltaNat (delta-arg_size)
3231          let code' = code `appOL` toOL [
3232                         MOV arg_rep (OpReg arg_reg) (OpAddr  (spRel 0)),
3233                         SUB wordRep (OpImm (ImmInt arg_size)) (OpReg rsp) ,
3234                         DELTA (delta-arg_size)]
3235          push_args rest code'
3236
3237        | otherwise = do
3238        -- we only ever generate word-sized function arguments.  Promotion
3239        -- has already happened: our Int8# type is kept sign-extended
3240        -- in an Int#, for example.
3241          ASSERT(arg_rep == I64) return ()
3242          (arg_op, arg_code) <- getOperand arg
3243          delta <- getDeltaNat
3244          setDeltaNat (delta-arg_size)
3245          let code' = code `appOL` toOL [PUSH I64 arg_op, 
3246                                         DELTA (delta-arg_size)]
3247          push_args rest code'
3248         where
3249           arg_rep = cmmExprRep arg
3250 #endif
3251
3252 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3253
3254 #if sparc_TARGET_ARCH
3255 {- 
3256    The SPARC calling convention is an absolute
3257    nightmare.  The first 6x32 bits of arguments are mapped into
3258    %o0 through %o5, and the remaining arguments are dumped to the
3259    stack, beginning at [%sp+92].  (Note that %o6 == %sp.)
3260
3261    If we have to put args on the stack, move %o6==%sp down by
3262    the number of words to go on the stack, to ensure there's enough space.
3263
3264    According to Fraser and Hanson's lcc book, page 478, fig 17.2,
3265    16 words above the stack pointer is a word for the address of
3266    a structure return value.  I use this as a temporary location
3267    for moving values from float to int regs.  Certainly it isn't
3268    safe to put anything in the 16 words starting at %sp, since
3269    this area can get trashed at any time due to window overflows
3270    caused by signal handlers.
3271
3272    A final complication (if the above isn't enough) is that 
3273    we can't blithely calculate the arguments one by one into
3274    %o0 .. %o5.  Consider the following nested calls:
3275
3276        fff a (fff b c)
3277
3278    Naive code moves a into %o0, and (fff b c) into %o1.  Unfortunately
3279    the inner call will itself use %o0, which trashes the value put there
3280    in preparation for the outer call.  Upshot: we need to calculate the
3281    args into temporary regs, and move those to arg regs or onto the
3282    stack only immediately prior to the call proper.  Sigh.
3283 -}
3284
3285 genCCall target dest_regs argsAndHints vols = do
3286     let
3287         args = map fst argsAndHints
3288     argcode_and_vregs <- mapM arg_to_int_vregs args
3289     let 
3290         (argcodes, vregss) = unzip argcode_and_vregs
3291         n_argRegs          = length allArgRegs
3292         n_argRegs_used     = min (length vregs) n_argRegs
3293         vregs              = concat vregss
3294     -- deal with static vs dynamic call targets
3295     callinsns <- (case target of
3296         CmmForeignCall (CmmLit (CmmLabel lbl)) conv -> do
3297                 return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))
3298         CmmForeignCall expr conv -> do
3299                 (dyn_c, [dyn_r]) <- arg_to_int_vregs expr
3300                 return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
3301         CmmPrim mop -> do
3302                   (res, reduce) <- outOfLineFloatOp mop
3303                   lblOrMopExpr <- case res of
3304                        Left lbl -> do
3305                             return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))
3306                        Right mopExpr -> do
3307                             (dyn_c, [dyn_r]) <- arg_to_int_vregs mopExpr
3308                             return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
3309                   if reduce then panic "genCCall(sparc): can not reduce" else return lblOrMopExpr
3310
3311       )
3312     let
3313         argcode = concatOL argcodes
3314         (move_sp_down, move_sp_up)
3315            = let diff = length vregs - n_argRegs
3316                  nn   = if odd diff then diff + 1 else diff -- keep 8-byte alignment
3317              in  if   nn <= 0
3318                  then (nilOL, nilOL)
3319                  else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
3320         transfer_code
3321            = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
3322     return (argcode       `appOL`
3323             move_sp_down  `appOL`
3324             transfer_code `appOL`
3325             callinsns     `appOL`
3326             unitOL NOP    `appOL`
3327             move_sp_up)
3328   where
3329      -- move args from the integer vregs into which they have been 
3330      -- marshalled, into %o0 .. %o5, and the rest onto the stack.
3331      move_final :: [Reg] -> [Reg] -> Int -> [Instr]
3332
3333      move_final [] _ offset          -- all args done
3334         = []
3335
3336      move_final (v:vs) [] offset     -- out of aregs; move to stack
3337         = ST I32 v (spRel offset)
3338           : move_final vs [] (offset+1)
3339
3340      move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
3341         = OR False g0 (RIReg v) a
3342           : move_final vs az offset
3343
3344      -- generate code to calculate an argument, and move it into one
3345      -- or two integer vregs.
3346      arg_to_int_vregs :: CmmExpr -> NatM (OrdList Instr, [Reg])
3347      arg_to_int_vregs arg
3348         | (cmmExprRep arg) == I64
3349         = do
3350           (ChildCode64 code r_lo) <- iselExpr64 arg
3351           let 
3352               r_hi = getHiVRegFromLo r_lo
3353           return (code, [r_hi, r_lo])
3354         | otherwise
3355         = do
3356           (src, code) <- getSomeReg arg
3357           tmp <- getNewRegNat (cmmExprRep arg)
3358           let
3359               pk   = cmmExprRep arg
3360           case pk of
3361              F64 -> do
3362                       v1 <- getNewRegNat I32
3363                       v2 <- getNewRegNat I32
3364                       return (
3365                         code                          `snocOL`
3366                         FMOV F64 src f0                `snocOL`
3367                         ST   F32  f0 (spRel 16)         `snocOL`
3368                         LD   I32  (spRel 16) v1         `snocOL`
3369                         ST   F32  (fPair f0) (spRel 16) `snocOL`
3370                         LD   I32  (spRel 16) v2
3371                         ,
3372                         [v1,v2]
3373                        )
3374              F32 -> do
3375                       v1 <- getNewRegNat I32
3376                       return (
3377                         code                    `snocOL`
3378                         ST   F32  src (spRel 16)  `snocOL`
3379                         LD   I32  (spRel 16) v1
3380                         ,
3381                         [v1]
3382                        )
3383              other -> do
3384                         v1 <- getNewRegNat I32
3385                         return (
3386                           code `snocOL` OR False g0 (RIReg src) v1
3387                           , 
3388                           [v1]
3389                          )
3390 outOfLineFloatOp mop =
3391     do
3392       mopExpr <- cmmMakeDynamicReference addImportNat True $
3393                   mkForeignLabel functionName Nothing True
3394       let mopLabelOrExpr = case mopExpr of
3395                         CmmLit (CmmLabel lbl) -> Left lbl
3396                         _ -> Right mopExpr
3397       return (mopLabelOrExpr, reduce)
3398             where
3399                 (reduce, functionName) = case mop of
3400                   MO_F32_Exp    -> (True,  FSLIT("exp"))
3401                   MO_F32_Log    -> (True,  FSLIT("log"))
3402                   MO_F32_Sqrt   -> (True,  FSLIT("sqrt"))
3403
3404                   MO_F32_Sin    -> (True,  FSLIT("sin"))
3405                   MO_F32_Cos    -> (True,  FSLIT("cos"))
3406                   MO_F32_Tan    -> (True,  FSLIT("tan"))
3407
3408                   MO_F32_Asin   -> (True,  FSLIT("asin"))
3409                   MO_F32_Acos   -> (True,  FSLIT("acos"))
3410                   MO_F32_Atan   -> (True,  FSLIT("atan"))
3411
3412                   MO_F32_Sinh   -> (True,  FSLIT("sinh"))
3413                   MO_F32_Cosh   -> (True,  FSLIT("cosh"))
3414                   MO_F32_Tanh   -> (True,  FSLIT("tanh"))
3415
3416                   MO_F64_Exp    -> (False, FSLIT("exp"))
3417                   MO_F64_Log    -> (False, FSLIT("log"))
3418                   MO_F64_Sqrt   -> (False, FSLIT("sqrt"))
3419
3420                   MO_F64_Sin    -> (False, FSLIT("sin"))
3421                   MO_F64_Cos    -> (False, FSLIT("cos"))
3422                   MO_F64_Tan    -> (False, FSLIT("tan"))
3423
3424                   MO_F64_Asin   -> (False, FSLIT("asin"))
3425                   MO_F64_Acos   -> (False, FSLIT("acos"))
3426                   MO_F64_Atan   -> (False, FSLIT("atan"))
3427
3428                   MO_F64_Sinh   -> (False, FSLIT("sinh"))
3429                   MO_F64_Cosh   -> (False, FSLIT("cosh"))
3430                   MO_F64_Tanh   -> (False, FSLIT("tanh"))
3431
3432                   other -> pprPanic "outOfLineFloatOp(sparc) "
3433                                 (pprCallishMachOp mop)
3434
3435 #endif /* sparc_TARGET_ARCH */
3436
3437 #if powerpc_TARGET_ARCH
3438
3439 #if darwin_TARGET_OS || linux_TARGET_OS
3440 {-
3441     The PowerPC calling convention for Darwin/Mac OS X
3442     is described in Apple's document
3443     "Inside Mac OS X - Mach-O Runtime Architecture".
3444     
3445     PowerPC Linux uses the System V Release 4 Calling Convention
3446     for PowerPC. It is described in the
3447     "System V Application Binary Interface PowerPC Processor Supplement".
3448
3449     Both conventions are similar:
3450     Parameters may be passed in general-purpose registers starting at r3, in
3451     floating point registers starting at f1, or on the stack. 
3452     
3453     But there are substantial differences:
3454     * The number of registers used for parameter passing and the exact set of
3455       nonvolatile registers differs (see MachRegs.lhs).
3456     * On Darwin, stack space is always reserved for parameters, even if they are
3457       passed in registers. The called routine may choose to save parameters from
3458       registers to the corresponding space on the stack.
3459     * On Darwin, a corresponding amount of GPRs is skipped when a floating point
3460       parameter is passed in an FPR.
3461     * SysV insists on either passing I64 arguments on the stack, or in two GPRs,
3462       starting with an odd-numbered GPR. It may skip a GPR to achieve this.
3463       Darwin just treats an I64 like two separate I32s (high word first).
3464     * I64 and F64 arguments are 8-byte aligned on the stack for SysV, but only
3465       4-byte aligned like everything else on Darwin.
3466     * The SysV spec claims that F32 is represented as F64 on the stack. GCC on
3467       PowerPC Linux does not agree, so neither do we.
3468       
3469     According to both conventions, The parameter area should be part of the
3470     caller's stack frame, allocated in the caller's prologue code (large enough
3471     to hold the parameter lists for all called routines). The NCG already
3472     uses the stack for register spilling, leaving 64 bytes free at the top.
3473     If we need a larger parameter area than that, we just allocate a new stack
3474     frame just before ccalling.
3475 -}
3476
3477 genCCall target dest_regs argsAndHints vols
3478   = ASSERT (not $ any (`elem` [I8,I16]) argReps)
3479         -- we rely on argument promotion in the codeGen
3480     do
3481         (finalStack,passArgumentsCode,usedRegs) <- passArguments
3482                                                         (zip args argReps)
3483                                                         allArgRegs allFPArgRegs
3484                                                         initialStackOffset
3485                                                         (toOL []) []
3486                                                 
3487         (labelOrExpr, reduceToF32) <- case target of
3488             CmmForeignCall (CmmLit (CmmLabel lbl)) conv -> return (Left lbl, False)
3489             CmmForeignCall expr conv -> return  (Right expr, False)
3490             CmmPrim mop -> outOfLineFloatOp mop
3491                                                         
3492         let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
3493             codeAfter = move_sp_up finalStack `appOL` moveResult reduceToF32
3494
3495         case labelOrExpr of
3496             Left lbl -> do
3497                 return (         codeBefore
3498                         `snocOL` BL lbl usedRegs
3499                         `appOL`  codeAfter)
3500             Right dyn -> do
3501                 (dynReg, dynCode) <- getSomeReg dyn
3502                 return (         dynCode
3503                         `snocOL` MTCTR dynReg
3504                         `appOL`  codeBefore
3505                         `snocOL` BCTRL usedRegs
3506                         `appOL`  codeAfter)
3507     where
3508 #if darwin_TARGET_OS
3509         initialStackOffset = 24
3510             -- size of linkage area + size of arguments, in bytes       
3511         stackDelta _finalStack = roundTo 16 $ (24 +) $ max 32 $ sum $
3512                                        map machRepByteWidth argReps
3513 #elif linux_TARGET_OS
3514         initialStackOffset = 8
3515         stackDelta finalStack = roundTo 16 finalStack
3516 #endif
3517         args = map fst argsAndHints
3518         argReps = map cmmExprRep args
3519
3520         roundTo a x | x `mod` a == 0 = x
3521                     | otherwise = x + a - (x `mod` a)
3522
3523         move_sp_down finalStack
3524                | delta > 64 =
3525                         toOL [STU I32 sp (AddrRegImm sp (ImmInt (-delta))),
3526                               DELTA (-delta)]
3527                | otherwise = nilOL
3528                where delta = stackDelta finalStack
3529         move_sp_up finalStack
3530                | delta > 64 =
3531                         toOL [ADD sp sp (RIImm (ImmInt delta)),
3532                               DELTA 0]
3533                | otherwise = nilOL
3534                where delta = stackDelta finalStack
3535                
3536
3537         passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)
3538         passArguments ((arg,I64):args) gprs fprs stackOffset
3539                accumCode accumUsed =
3540             do
3541                 ChildCode64 code vr_lo <- iselExpr64 arg
3542                 let vr_hi = getHiVRegFromLo vr_lo
3543
3544 #if darwin_TARGET_OS                
3545                 passArguments args
3546                               (drop 2 gprs)
3547                               fprs
3548                               (stackOffset+8)
3549                               (accumCode `appOL` code
3550                                     `snocOL` storeWord vr_hi gprs stackOffset
3551                                     `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))
3552                               ((take 2 gprs) ++ accumUsed)
3553             where
3554                 storeWord vr (gpr:_) offset = MR gpr vr
3555                 storeWord vr [] offset = ST I32 vr (AddrRegImm sp (ImmInt offset))
3556                 
3557 #elif linux_TARGET_OS
3558                 let stackOffset' = roundTo 8 stackOffset
3559                     stackCode = accumCode `appOL` code
3560                         `snocOL` ST I32 vr_hi (AddrRegImm sp (ImmInt stackOffset'))
3561                         `snocOL` ST I32 vr_lo (AddrRegImm sp (ImmInt (stackOffset'+4)))
3562                     regCode hireg loreg =
3563                         accumCode `appOL` code
3564                             `snocOL` MR hireg vr_hi
3565                             `snocOL` MR loreg vr_lo
3566                                         
3567                 case gprs of
3568                     hireg : loreg : regs | even (length gprs) ->
3569                         passArguments args regs fprs stackOffset
3570                                       (regCode hireg loreg) (hireg : loreg : accumUsed)
3571                     _skipped : hireg : loreg : regs ->
3572                         passArguments args regs fprs stackOffset
3573                                       (regCode hireg loreg) (hireg : loreg : accumUsed)
3574                     _ -> -- only one or no regs left
3575                         passArguments args [] fprs (stackOffset'+8)
3576                                       stackCode accumUsed
3577 #endif
3578         
3579         passArguments ((arg,rep):args) gprs fprs stackOffset accumCode accumUsed
3580             | reg : _ <- regs = do
3581                 register <- getRegister arg
3582                 let code = case register of
3583                             Fixed _ freg fcode -> fcode `snocOL` MR reg freg
3584                             Any _ acode -> acode reg
3585                 passArguments args
3586                               (drop nGprs gprs)
3587                               (drop nFprs fprs)
3588 #if darwin_TARGET_OS
3589         -- The Darwin ABI requires that we reserve stack slots for register parameters
3590                               (stackOffset + stackBytes)
3591 #elif linux_TARGET_OS
3592         -- ... the SysV ABI doesn't.
3593                               stackOffset
3594 #endif
3595                               (accumCode `appOL` code)
3596                               (reg : accumUsed)
3597             | otherwise = do
3598                 (vr, code) <- getSomeReg arg
3599                 passArguments args
3600                               (drop nGprs gprs)
3601                               (drop nFprs fprs)
3602                               (stackOffset' + stackBytes)
3603                               (accumCode `appOL` code `snocOL` ST rep vr stackSlot)
3604                               accumUsed
3605             where
3606 #if darwin_TARGET_OS
3607         -- stackOffset is at least 4-byte aligned
3608         -- The Darwin ABI is happy with that.
3609                 stackOffset' = stackOffset
3610 #else
3611         -- ... the SysV ABI requires 8-byte alignment for doubles.
3612                 stackOffset' | rep == F64 = roundTo 8 stackOffset
3613                              | otherwise  =           stackOffset
3614 #endif
3615                 stackSlot = AddrRegImm sp (ImmInt stackOffset')
3616                 (nGprs, nFprs, stackBytes, regs) = case rep of
3617                     I32 -> (1, 0, 4, gprs)
3618 #if darwin_TARGET_OS
3619         -- The Darwin ABI requires that we skip a corresponding number of GPRs when
3620         -- we use the FPRs.
3621                     F32 -> (1, 1, 4, fprs)
3622                     F64 -> (2, 1, 8, fprs)
3623 #elif linux_TARGET_OS
3624         -- ... the SysV ABI doesn't.
3625                     F32 -> (0, 1, 4, fprs)
3626                     F64 -> (0, 1, 8, fprs)
3627 #endif
3628         
3629         moveResult reduceToF32 =
3630             case dest_regs of
3631                 [] -> nilOL
3632                 [(dest, _hint)]
3633                     | reduceToF32 && rep == F32 -> unitOL (FRSP r_dest f1)
3634                     | rep == F32 || rep == F64 -> unitOL (MR r_dest f1)
3635                     | rep == I64 -> toOL [MR (getHiVRegFromLo r_dest) r3,
3636                                           MR r_dest r4]
3637                     | otherwise -> unitOL (MR r_dest r3)
3638                     where rep = cmmRegRep dest
3639                           r_dest = getRegisterReg dest
3640                           
3641         outOfLineFloatOp mop =
3642             do
3643                 mopExpr <- cmmMakeDynamicReference addImportNat True $
3644                               mkForeignLabel functionName Nothing True
3645                 let mopLabelOrExpr = case mopExpr of
3646                         CmmLit (CmmLabel lbl) -> Left lbl
3647                         _ -> Right mopExpr
3648                 return (mopLabelOrExpr, reduce)
3649             where
3650                 (functionName, reduce) = case mop of
3651                     MO_F32_Exp   -> (FSLIT("exp"), True)
3652                     MO_F32_Log   -> (FSLIT("log"), True)
3653                     MO_F32_Sqrt  -> (FSLIT("sqrt"), True)
3654                         
3655                     MO_F32_Sin   -> (FSLIT("sin"), True)
3656                     MO_F32_Cos   -> (FSLIT("cos"), True)
3657                     MO_F32_Tan   -> (FSLIT("tan"), True)
3658                     
3659                     MO_F32_Asin  -> (FSLIT("asin"), True)
3660                     MO_F32_Acos  -> (FSLIT("acos"), True)
3661                     MO_F32_Atan  -> (FSLIT("atan"), True)
3662                     
3663                     MO_F32_Sinh  -> (FSLIT("sinh"), True)
3664                     MO_F32_Cosh  -> (FSLIT("cosh"), True)
3665                     MO_F32_Tanh  -> (FSLIT("tanh"), True)
3666                     MO_F32_Pwr   -> (FSLIT("pow"), True)
3667                         
3668                     MO_F64_Exp   -> (FSLIT("exp"), False)
3669                     MO_F64_Log   -> (FSLIT("log"), False)
3670                     MO_F64_Sqrt  -> (FSLIT("sqrt"), False)
3671                         
3672                     MO_F64_Sin   -> (FSLIT("sin"), False)
3673                     MO_F64_Cos   -> (FSLIT("cos"), False)
3674                     MO_F64_Tan   -> (FSLIT("tan"), False)
3675                      
3676                     MO_F64_Asin  -> (FSLIT("asin"), False)
3677                     MO_F64_Acos  -> (FSLIT("acos"), False)
3678                     MO_F64_Atan  -> (FSLIT("atan"), False)
3679                     
3680                     MO_F64_Sinh  -> (FSLIT("sinh"), False)
3681                     MO_F64_Cosh  -> (FSLIT("cosh"), False)
3682                     MO_F64_Tanh  -> (FSLIT("tanh"), False)
3683                     MO_F64_Pwr   -> (FSLIT("pow"), False)
3684                     other -> pprPanic "genCCall(ppc): unknown callish op"
3685                                     (pprCallishMachOp other)
3686
3687 #endif /* darwin_TARGET_OS || linux_TARGET_OS */
3688                 
3689 #endif /* powerpc_TARGET_ARCH */
3690
3691
3692 -- -----------------------------------------------------------------------------
3693 -- Generating a table-branch
3694
3695 genSwitch :: CmmExpr -> [Maybe BlockId] -> NatM InstrBlock
3696
3697 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
3698 genSwitch expr ids = do
3699   (reg,e_code) <- getSomeReg expr
3700   lbl <- getNewLabelNat
3701   let
3702         jumpTable = map jumpTableEntry ids
3703         op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg wORD_SIZE) (ImmCLbl lbl))
3704         code = e_code `appOL` toOL [
3705                 LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
3706                 JMP_TBL op [ id | Just id <- ids ]
3707              ]
3708   -- in
3709   return code
3710 #elif powerpc_TARGET_ARCH
3711 genSwitch expr ids 
3712   | opt_PIC
3713   = do
3714         (reg,e_code) <- getSomeReg expr
3715         tmp <- getNewRegNat I32
3716         lbl <- getNewLabelNat
3717         dynRef <- cmmMakeDynamicReference addImportNat False lbl
3718         (tableReg,t_code) <- getSomeReg $ dynRef
3719         let
3720             jumpTable = map jumpTableEntryRel ids
3721             
3722             jumpTableEntryRel Nothing
3723                 = CmmStaticLit (CmmInt 0 wordRep)
3724             jumpTableEntryRel (Just (BlockId id))
3725                 = CmmStaticLit (CmmLabelDiffOff blockLabel lbl 0)
3726                 where blockLabel = mkAsmTempLabel id
3727
3728             code = e_code `appOL` t_code `appOL` toOL [
3729                             LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
3730                             SLW tmp reg (RIImm (ImmInt 2)),
3731                             LD I32 tmp (AddrRegReg tableReg tmp),
3732                             ADD tmp tmp (RIReg tableReg),
3733                             MTCTR tmp,
3734                             BCTR [ id | Just id <- ids ]
3735                     ]
3736         return code
3737   | otherwise
3738   = do
3739         (reg,e_code) <- getSomeReg expr
3740         tmp <- getNewRegNat I32
3741         lbl <- getNewLabelNat
3742         let
3743             jumpTable = map jumpTableEntry ids
3744         
3745             code = e_code `appOL` toOL [
3746                             LDATA ReadOnlyData (CmmDataLabel lbl : jumpTable),
3747                             SLW tmp reg (RIImm (ImmInt 2)),
3748                             ADDIS tmp tmp (HA (ImmCLbl lbl)),
3749                             LD I32 tmp (AddrRegImm tmp (LO (ImmCLbl lbl))),
3750                             MTCTR tmp,
3751                             BCTR [ id | Just id <- ids ]
3752                     ]
3753         return code
3754 #else
3755 genSwitch expr ids = panic "ToDo: genSwitch"
3756 #endif
3757
3758 jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordRep)
3759 jumpTableEntry (Just (BlockId id)) = CmmStaticLit (CmmLabel blockLabel)
3760     where blockLabel = mkAsmTempLabel id
3761
3762 -- -----------------------------------------------------------------------------
3763 -- Support bits
3764 -- -----------------------------------------------------------------------------
3765
3766
3767 -- -----------------------------------------------------------------------------
3768 -- 'condIntReg' and 'condFltReg': condition codes into registers
3769
3770 -- Turn those condition codes into integers now (when they appear on
3771 -- the right hand side of an assignment).
3772 -- 
3773 -- (If applicable) Do not fill the delay slots here; you will confuse the
3774 -- register allocator.
3775
3776 condIntReg, condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register
3777
3778 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3779
3780 #if alpha_TARGET_ARCH
3781 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
3782 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
3783 #endif /* alpha_TARGET_ARCH */
3784
3785 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3786
3787 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
3788
3789 condIntReg cond x y = do
3790   CondCode _ cond cond_code <- condIntCode cond x y
3791   tmp <- getNewRegNat I8
3792   let 
3793         code dst = cond_code `appOL` toOL [
3794                     SETCC cond (OpReg tmp),
3795                     MOVZxL I8 (OpReg tmp) (OpReg dst)
3796                   ]
3797   -- in
3798   return (Any I32 code)
3799
3800 #endif
3801
3802 #if i386_TARGET_ARCH
3803
3804 condFltReg cond x y = do
3805   CondCode _ cond cond_code <- condFltCode cond x y
3806   tmp <- getNewRegNat I8
3807   let 
3808         code dst = cond_code `appOL` toOL [
3809                     SETCC cond (OpReg tmp),
3810                     MOVZxL I8 (OpReg tmp) (OpReg dst)
3811                   ]
3812   -- in
3813   return (Any I32 code)
3814
3815 #endif
3816
3817 #if x86_64_TARGET_ARCH
3818
3819 condFltReg cond x y = do
3820   CondCode _ cond cond_code <- condFltCode cond x y
3821   tmp1 <- getNewRegNat wordRep
3822   tmp2 <- getNewRegNat wordRep
3823   let 
3824         -- We have to worry about unordered operands (eg. comparisons
3825         -- against NaN).  If the operands are unordered, the comparison
3826         -- sets the parity flag, carry flag and zero flag.
3827         -- All comparisons are supposed to return false for unordered
3828         -- operands except for !=, which returns true.
3829         --
3830         -- Optimisation: we don't have to test the parity flag if we
3831         -- know the test has already excluded the unordered case: eg >
3832         -- and >= test for a zero carry flag, which can only occur for
3833         -- ordered operands.
3834         --
3835         -- ToDo: by reversing comparisons we could avoid testing the
3836         -- parity flag in more cases.
3837
3838         code dst = 
3839            cond_code `appOL` 
3840              (case cond of
3841                 NE  -> or_unordered dst
3842                 GU  -> plain_test   dst
3843                 GEU -> plain_test   dst
3844                 _   -> and_ordered  dst)
3845
3846         plain_test dst = toOL [
3847                     SETCC cond (OpReg tmp1),
3848                     MOVZxL I8 (OpReg tmp1) (OpReg dst)
3849                  ]
3850         or_unordered dst = toOL [
3851                     SETCC cond (OpReg tmp1),
3852                     SETCC PARITY (OpReg tmp2),
3853                     OR I8 (OpReg tmp1) (OpReg tmp2),
3854                     MOVZxL I8 (OpReg tmp2) (OpReg dst)
3855                   ]
3856         and_ordered dst = toOL [
3857                     SETCC cond (OpReg tmp1),
3858                     SETCC NOTPARITY (OpReg tmp2),
3859                     AND I8 (OpReg tmp1) (OpReg tmp2),
3860                     MOVZxL I8 (OpReg tmp2) (OpReg dst)
3861                   ]
3862   -- in
3863   return (Any I32 code)
3864
3865 #endif
3866
3867 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3868
3869 #if sparc_TARGET_ARCH
3870
3871 condIntReg EQQ x (CmmLit (CmmInt 0 d)) = do
3872     (src, code) <- getSomeReg x
3873     tmp <- getNewRegNat I32
3874     let
3875         code__2 dst = code `appOL` toOL [
3876             SUB False True g0 (RIReg src) g0,
3877             SUB True False g0 (RIImm (ImmInt (-1))) dst]
3878     return (Any I32 code__2)
3879
3880 condIntReg EQQ x y = do
3881     (src1, code1) <- getSomeReg x
3882     (src2, code2) <- getSomeReg y
3883     tmp1 <- getNewRegNat I32
3884     tmp2 <- getNewRegNat I32
3885     let
3886         code__2 dst = code1 `appOL` code2 `appOL` toOL [
3887             XOR False src1 (RIReg src2) dst,
3888             SUB False True g0 (RIReg dst) g0,
3889             SUB True False g0 (RIImm (ImmInt (-1))) dst]
3890     return (Any I32 code__2)
3891
3892 condIntReg NE x (CmmLit (CmmInt 0 d)) = do
3893     (src, code) <- getSomeReg x
3894     tmp <- getNewRegNat I32
3895     let
3896         code__2 dst = code `appOL` toOL [
3897             SUB False True g0 (RIReg src) g0,
3898             ADD True False g0 (RIImm (ImmInt 0)) dst]
3899     return (Any I32 code__2)
3900
3901 condIntReg NE x y = do
3902     (src1, code1) <- getSomeReg x
3903     (src2, code2) <- getSomeReg y
3904     tmp1 <- getNewRegNat I32
3905     tmp2 <- getNewRegNat I32
3906     let
3907         code__2 dst = code1 `appOL` code2 `appOL` toOL [
3908             XOR False src1 (RIReg src2) dst,
3909             SUB False True g0 (RIReg dst) g0,
3910             ADD True False g0 (RIImm (ImmInt 0)) dst]
3911     return (Any I32 code__2)
3912
3913 condIntReg cond x y = do
3914     BlockId lbl1 <- getBlockIdNat
3915     BlockId lbl2 <- getBlockIdNat
3916     CondCode _ cond cond_code <- condIntCode cond x y
3917     let
3918         code__2 dst = cond_code `appOL` toOL [
3919             BI cond False (ImmCLbl (mkAsmTempLabel lbl1)), NOP,
3920             OR False g0 (RIImm (ImmInt 0)) dst,
3921             BI ALWAYS False (ImmCLbl (mkAsmTempLabel lbl2)), NOP,
3922             NEWBLOCK (BlockId lbl1),
3923             OR False g0 (RIImm (ImmInt 1)) dst,
3924             NEWBLOCK (BlockId lbl2)]
3925     return (Any I32 code__2)
3926
3927 condFltReg cond x y = do
3928     BlockId lbl1 <- getBlockIdNat
3929     BlockId lbl2 <- getBlockIdNat
3930     CondCode _ cond cond_code <- condFltCode cond x y
3931     let
3932         code__2 dst = cond_code `appOL` toOL [ 
3933             NOP,
3934             BF cond False (ImmCLbl (mkAsmTempLabel lbl1)), NOP,
3935             OR False g0 (RIImm (ImmInt 0)) dst,
3936             BI ALWAYS False (ImmCLbl (mkAsmTempLabel lbl2)), NOP,
3937             NEWBLOCK (BlockId lbl1),
3938             OR False g0 (RIImm (ImmInt 1)) dst,
3939             NEWBLOCK (BlockId lbl2)]
3940     return (Any I32 code__2)
3941
3942 #endif /* sparc_TARGET_ARCH */
3943
3944 #if powerpc_TARGET_ARCH
3945 condReg getCond = do
3946     lbl1 <- getBlockIdNat
3947     lbl2 <- getBlockIdNat
3948     CondCode _ cond cond_code <- getCond
3949     let
3950 {-        code dst = cond_code `appOL` toOL [
3951                 BCC cond lbl1,
3952                 LI dst (ImmInt 0),
3953                 BCC ALWAYS lbl2,
3954                 NEWBLOCK lbl1,
3955                 LI dst (ImmInt 1),
3956                 BCC ALWAYS lbl2,
3957                 NEWBLOCK lbl2
3958             ]-}
3959         code dst = cond_code
3960             `appOL` negate_code
3961             `appOL` toOL [
3962                 MFCR dst,
3963                 RLWINM dst dst (bit + 1) 31 31
3964             ]
3965         
3966         negate_code | do_negate = unitOL (CRNOR bit bit bit)
3967                     | otherwise = nilOL
3968                     
3969         (bit, do_negate) = case cond of
3970             LTT -> (0, False)
3971             LE  -> (1, True)
3972             EQQ -> (2, False)
3973             GE  -> (0, True)
3974             GTT -> (1, False)
3975             
3976             NE  -> (2, True)
3977             
3978             LU  -> (0, False)
3979             LEU -> (1, True)
3980             GEU -> (0, True)
3981             GU  -> (1, False)
3982                 
3983     return (Any I32 code)
3984     
3985 condIntReg cond x y = condReg (condIntCode cond x y)
3986 condFltReg cond x y = condReg (condFltCode cond x y)
3987 #endif /* powerpc_TARGET_ARCH */
3988
3989
3990 -- -----------------------------------------------------------------------------
3991 -- 'trivial*Code': deal with trivial instructions
3992
3993 -- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',
3994 -- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.
3995 -- Only look for constants on the right hand side, because that's
3996 -- where the generic optimizer will have put them.
3997
3998 -- Similarly, for unary instructions, we don't have to worry about
3999 -- matching an StInt as the argument, because genericOpt will already
4000 -- have handled the constant-folding.
4001
4002 trivialCode
4003     :: MachRep 
4004     -> IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
4005       ,IF_ARCH_i386 ((Operand -> Operand -> Instr) 
4006                      -> Maybe (Operand -> Operand -> Instr)
4007       ,IF_ARCH_x86_64 ((Operand -> Operand -> Instr) 
4008                      -> Maybe (Operand -> Operand -> Instr)
4009       ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
4010       ,IF_ARCH_powerpc(Bool -> (Reg -> Reg -> RI -> Instr)
4011       ,)))))
4012     -> CmmExpr -> CmmExpr -- the two arguments
4013     -> NatM Register
4014
4015 #ifndef powerpc_TARGET_ARCH
4016 trivialFCode
4017     :: MachRep
4018     -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
4019       ,IF_ARCH_sparc((MachRep -> Reg -> Reg -> Reg -> Instr)
4020       ,IF_ARCH_i386 ((MachRep -> Reg -> Reg -> Reg -> Instr)
4021       ,IF_ARCH_x86_64 ((MachRep -> Operand -> Operand -> Instr)
4022       ,))))
4023     -> CmmExpr -> CmmExpr -- the two arguments
4024     -> NatM Register
4025 #endif
4026
4027 trivialUCode
4028     :: MachRep 
4029     -> IF_ARCH_alpha((RI -> Reg -> Instr)
4030       ,IF_ARCH_i386 ((Operand -> Instr)
4031       ,IF_ARCH_x86_64 ((Operand -> Instr)
4032       ,IF_ARCH_sparc((RI -> Reg -> Instr)
4033       ,IF_ARCH_powerpc((Reg -> Reg -> Instr)
4034       ,)))))
4035     -> CmmExpr  -- the one argument
4036     -> NatM Register
4037
4038 #ifndef powerpc_TARGET_ARCH
4039 trivialUFCode
4040     :: MachRep
4041     -> IF_ARCH_alpha((Reg -> Reg -> Instr)
4042       ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
4043       ,IF_ARCH_x86_64 ((Reg -> Reg -> Instr)
4044       ,IF_ARCH_sparc((Reg -> Reg -> Instr)
4045       ,))))
4046     -> CmmExpr -- the one argument
4047     -> NatM Register
4048 #endif
4049
4050 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4051
4052 #if alpha_TARGET_ARCH
4053
4054 trivialCode instr x (StInt y)
4055   | fits8Bits y
4056   = getRegister x               `thenNat` \ register ->
4057     getNewRegNat IntRep         `thenNat` \ tmp ->
4058     let
4059         code = registerCode register tmp
4060         src1 = registerName register tmp
4061         src2 = ImmInt (fromInteger y)
4062         code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
4063     in
4064     return (Any IntRep code__2)
4065
4066 trivialCode instr x y
4067   = getRegister x               `thenNat` \ register1 ->
4068     getRegister y               `thenNat` \ register2 ->
4069     getNewRegNat IntRep         `thenNat` \ tmp1 ->
4070     getNewRegNat IntRep         `thenNat` \ tmp2 ->
4071     let
4072         code1 = registerCode register1 tmp1 []
4073         src1  = registerName register1 tmp1
4074         code2 = registerCode register2 tmp2 []
4075         src2  = registerName register2 tmp2
4076         code__2 dst = asmSeqThen [code1, code2] .
4077                      mkSeqInstr (instr src1 (RIReg src2) dst)
4078     in
4079     return (Any IntRep code__2)
4080
4081 ------------
4082 trivialUCode instr x
4083   = getRegister x               `thenNat` \ register ->
4084     getNewRegNat IntRep         `thenNat` \ tmp ->
4085     let
4086         code = registerCode register tmp
4087         src  = registerName register tmp
4088         code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
4089     in
4090     return (Any IntRep code__2)
4091
4092 ------------
4093 trivialFCode _ instr x y
4094   = getRegister x               `thenNat` \ register1 ->
4095     getRegister y               `thenNat` \ register2 ->
4096     getNewRegNat F64    `thenNat` \ tmp1 ->
4097     getNewRegNat F64    `thenNat` \ tmp2 ->
4098     let
4099         code1 = registerCode register1 tmp1
4100         src1  = registerName register1 tmp1
4101
4102         code2 = registerCode register2 tmp2
4103         src2  = registerName register2 tmp2
4104
4105         code__2 dst = asmSeqThen [code1 [], code2 []] .
4106                       mkSeqInstr (instr src1 src2 dst)
4107     in
4108     return (Any F64 code__2)
4109
4110 trivialUFCode _ instr x
4111   = getRegister x               `thenNat` \ register ->
4112     getNewRegNat F64    `thenNat` \ tmp ->
4113     let
4114         code = registerCode register tmp
4115         src  = registerName register tmp
4116         code__2 dst = code . mkSeqInstr (instr src dst)
4117     in
4118     return (Any F64 code__2)
4119
4120 #endif /* alpha_TARGET_ARCH */
4121
4122 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4123
4124 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
4125
4126 {-
4127 The Rules of the Game are:
4128
4129 * You cannot assume anything about the destination register dst;
4130   it may be anything, including a fixed reg.
4131
4132 * You may compute an operand into a fixed reg, but you may not 
4133   subsequently change the contents of that fixed reg.  If you
4134   want to do so, first copy the value either to a temporary
4135   or into dst.  You are free to modify dst even if it happens
4136   to be a fixed reg -- that's not your problem.
4137
4138 * You cannot assume that a fixed reg will stay live over an
4139   arbitrary computation.  The same applies to the dst reg.
4140
4141 * Temporary regs obtained from getNewRegNat are distinct from 
4142   each other and from all other regs, and stay live over 
4143   arbitrary computations.
4144
4145 --------------------
4146
4147 SDM's version of The Rules:
4148
4149 * If getRegister returns Any, that means it can generate correct
4150   code which places the result in any register, period.  Even if that
4151   register happens to be read during the computation.
4152
4153   Corollary #1: this means that if you are generating code for an
4154   operation with two arbitrary operands, you cannot assign the result
4155   of the first operand into the destination register before computing
4156   the second operand.  The second operand might require the old value
4157   of the destination register.
4158
4159   Corollary #2: A function might be able to generate more efficient
4160   code if it knows the destination register is a new temporary (and
4161   therefore not read by any of the sub-computations).
4162
4163 * If getRegister returns Any, then the code it generates may modify only:
4164         (a) fresh temporaries
4165         (b) the destination register
4166         (c) known registers (eg. %ecx is used by shifts)
4167   In particular, it may *not* modify global registers, unless the global
4168   register happens to be the destination register.
4169 -}
4170
4171 trivialCode rep instr (Just revinstr) (CmmLit lit_a) b
4172   | not (is64BitLit lit_a) = do
4173   b_code <- getAnyReg b
4174   let
4175        code dst 
4176          = b_code dst `snocOL`
4177            revinstr (OpImm (litToImm lit_a)) (OpReg dst)
4178   -- in
4179   return (Any rep code)
4180
4181 trivialCode rep instr maybe_revinstr a b = genTrivialCode rep instr a b
4182
4183 -- This is re-used for floating pt instructions too.
4184 genTrivialCode rep instr a b = do
4185   (b_op, b_code) <- getNonClobberedOperand b
4186   a_code <- getAnyReg a
4187   tmp <- getNewRegNat rep
4188   let
4189      -- We want the value of b to stay alive across the computation of a.
4190      -- But, we want to calculate a straight into the destination register,
4191      -- because the instruction only has two operands (dst := dst `op` src).
4192      -- The troublesome case is when the result of b is in the same register
4193      -- as the destination reg.  In this case, we have to save b in a
4194      -- new temporary across the computation of a.
4195      code dst
4196         | dst `regClashesWithOp` b_op =
4197                 b_code `appOL`
4198                 unitOL (MOV rep b_op (OpReg tmp)) `appOL`
4199                 a_code dst `snocOL`
4200                 instr (OpReg tmp) (OpReg dst)
4201         | otherwise =
4202                 b_code `appOL`
4203                 a_code dst `snocOL`
4204                 instr b_op (OpReg dst)
4205   -- in
4206   return (Any rep code)
4207
4208 reg `regClashesWithOp` OpReg reg2   = reg == reg2
4209 reg `regClashesWithOp` OpAddr amode = any (==reg) (addrModeRegs amode)
4210 reg `regClashesWithOp` _            = False
4211
4212 -----------
4213
4214 trivialUCode rep instr x = do
4215   x_code <- getAnyReg x
4216   let
4217      code dst =
4218         x_code dst `snocOL`
4219         instr (OpReg dst)
4220   -- in
4221   return (Any rep code)
4222
4223 -----------
4224
4225 #if i386_TARGET_ARCH
4226
4227 trivialFCode pk instr x y = do
4228   (x_reg, x_code) <- getNonClobberedReg x -- these work for float regs too
4229   (y_reg, y_code) <- getSomeReg y
4230   let
4231      code dst =
4232         x_code `appOL`
4233         y_code `snocOL`
4234         instr pk x_reg y_reg dst
4235   -- in
4236   return (Any pk code)
4237
4238 #endif
4239
4240 #if x86_64_TARGET_ARCH
4241
4242 trivialFCode pk instr x y = genTrivialCode  pk (instr pk) x y
4243
4244 #endif
4245
4246 -------------
4247
4248 trivialUFCode rep instr x = do
4249   (x_reg, x_code) <- getSomeReg x
4250   let
4251      code dst =
4252         x_code `snocOL`
4253         instr x_reg dst
4254   -- in
4255   return (Any rep code)
4256
4257 #endif /* i386_TARGET_ARCH */
4258
4259 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4260
4261 #if sparc_TARGET_ARCH
4262
4263 trivialCode pk instr x (CmmLit (CmmInt y d))
4264   | fits13Bits y
4265   = do
4266       (src1, code) <- getSomeReg x
4267       tmp <- getNewRegNat I32
4268       let
4269         src2 = ImmInt (fromInteger y)
4270         code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
4271       return (Any I32 code__2)
4272
4273 trivialCode pk instr x y = do
4274     (src1, code1) <- getSomeReg x
4275     (src2, code2) <- getSomeReg y
4276     tmp1 <- getNewRegNat I32
4277     tmp2 <- getNewRegNat I32
4278     let
4279         code__2 dst = code1 `appOL` code2 `snocOL`
4280                       instr src1 (RIReg src2) dst
4281     return (Any I32 code__2)
4282
4283 ------------
4284 trivialFCode pk instr x y = do
4285     (src1, code1) <- getSomeReg x
4286     (src2, code2) <- getSomeReg y
4287     tmp1 <- getNewRegNat (cmmExprRep x)
4288     tmp2 <- getNewRegNat (cmmExprRep y)
4289     tmp <- getNewRegNat F64
4290     let
4291         promote x = FxTOy F32 F64 x tmp
4292
4293         pk1   = cmmExprRep x
4294         pk2   = cmmExprRep y
4295
4296         code__2 dst =
4297                 if pk1 == pk2 then
4298                     code1 `appOL` code2 `snocOL`
4299                     instr pk src1 src2 dst
4300                 else if pk1 == F32 then
4301                     code1 `snocOL` promote src1 `appOL` code2 `snocOL`
4302                     instr F64 tmp src2 dst
4303                 else
4304                     code1 `appOL` code2 `snocOL` promote src2 `snocOL`
4305                     instr F64 src1 tmp dst
4306     return (Any (if pk1 == pk2 then pk1 else F64) code__2)
4307
4308 ------------
4309 trivialUCode pk instr x = do
4310     (src, code) <- getSomeReg x
4311     tmp <- getNewRegNat pk
4312     let
4313         code__2 dst = code `snocOL` instr (RIReg src) dst
4314     return (Any pk code__2)
4315
4316 -------------
4317 trivialUFCode pk instr x = do
4318     (src, code) <- getSomeReg x
4319     tmp <- getNewRegNat pk
4320     let
4321         code__2 dst = code `snocOL` instr src dst
4322     return (Any pk code__2)
4323
4324 #endif /* sparc_TARGET_ARCH */
4325
4326 #if powerpc_TARGET_ARCH
4327
4328 {-
4329 Wolfgang's PowerPC version of The Rules:
4330
4331 A slightly modified version of The Rules to take advantage of the fact
4332 that PowerPC instructions work on all registers and don't implicitly
4333 clobber any fixed registers.
4334
4335 * The only expression for which getRegister returns Fixed is (CmmReg reg).
4336
4337 * If getRegister returns Any, then the code it generates may modify only:
4338         (a) fresh temporaries
4339         (b) the destination register
4340   It may *not* modify global registers, unless the global
4341   register happens to be the destination register.
4342   It may not clobber any other registers. In fact, only ccalls clobber any
4343   fixed registers.
4344   Also, it may not modify the counter register (used by genCCall).
4345   
4346   Corollary: If a getRegister for a subexpression returns Fixed, you need
4347   not move it to a fresh temporary before evaluating the next subexpression.
4348   The Fixed register won't be modified.
4349   Therefore, we don't need a counterpart for the x86's getStableReg on PPC.
4350   
4351 * SDM's First Rule is valid for PowerPC, too: subexpressions can depend on
4352   the value of the destination register.
4353 -}
4354
4355 trivialCode rep signed instr x (CmmLit (CmmInt y _))
4356     | Just imm <- makeImmediate rep signed y 
4357     = do
4358         (src1, code1) <- getSomeReg x
4359         let code dst = code1 `snocOL` instr dst src1 (RIImm imm)
4360         return (Any rep code)
4361   
4362 trivialCode rep signed instr x y = do
4363     (src1, code1) <- getSomeReg x
4364     (src2, code2) <- getSomeReg y
4365     let code dst = code1 `appOL` code2 `snocOL` instr dst src1 (RIReg src2)
4366     return (Any rep code)
4367
4368 trivialCodeNoImm :: MachRep -> (Reg -> Reg -> Reg -> Instr)
4369     -> CmmExpr -> CmmExpr -> NatM Register
4370 trivialCodeNoImm rep instr x y = do
4371     (src1, code1) <- getSomeReg x
4372     (src2, code2) <- getSomeReg y
4373     let code dst = code1 `appOL` code2 `snocOL` instr dst src1 src2
4374     return (Any rep code)
4375     
4376 trivialUCode rep instr x = do
4377     (src, code) <- getSomeReg x
4378     let code' dst = code `snocOL` instr dst src
4379     return (Any rep code')
4380     
4381 -- There is no "remainder" instruction on the PPC, so we have to do
4382 -- it the hard way.
4383 -- The "div" parameter is the division instruction to use (DIVW or DIVWU)
4384
4385 remainderCode :: MachRep -> (Reg -> Reg -> Reg -> Instr)
4386     -> CmmExpr -> CmmExpr -> NatM Register
4387 remainderCode rep div x y = do
4388     (src1, code1) <- getSomeReg x
4389     (src2, code2) <- getSomeReg y
4390     let code dst = code1 `appOL` code2 `appOL` toOL [
4391                 div dst src1 src2,
4392                 MULLW dst dst (RIReg src2),
4393                 SUBF dst dst src1
4394             ]
4395     return (Any rep code)
4396
4397 #endif /* powerpc_TARGET_ARCH */
4398
4399
4400 -- -----------------------------------------------------------------------------
4401 --  Coercing to/from integer/floating-point...
4402
4403 -- @coerce(Int2FP|FP2Int)@ are more complicated integer/float
4404 -- conversions.  We have to store temporaries in memory to move
4405 -- between the integer and the floating point register sets.
4406
4407 -- @coerceDbl2Flt@ and @coerceFlt2Dbl@ are done this way because we
4408 -- pretend, on sparc at least, that double and float regs are seperate
4409 -- kinds, so the value has to be computed into one kind before being
4410 -- explicitly "converted" to live in the other kind.
4411
4412 coerceInt2FP :: MachRep -> MachRep -> CmmExpr -> NatM Register
4413 coerceFP2Int :: MachRep -> MachRep -> CmmExpr -> NatM Register
4414
4415 #if sparc_TARGET_ARCH
4416 coerceDbl2Flt :: CmmExpr -> NatM Register
4417 coerceFlt2Dbl :: CmmExpr -> NatM Register
4418 #endif
4419
4420 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4421
4422 #if alpha_TARGET_ARCH
4423
4424 coerceInt2FP _ x
4425   = getRegister x               `thenNat` \ register ->
4426     getNewRegNat IntRep         `thenNat` \ reg ->
4427     let
4428         code = registerCode register reg
4429         src  = registerName register reg
4430
4431         code__2 dst = code . mkSeqInstrs [
4432             ST Q src (spRel 0),
4433             LD TF dst (spRel 0),
4434             CVTxy Q TF dst dst]
4435     in
4436     return (Any F64 code__2)
4437
4438 -------------
4439 coerceFP2Int x
4440   = getRegister x               `thenNat` \ register ->
4441     getNewRegNat F64    `thenNat` \ tmp ->
4442     let
4443         code = registerCode register tmp
4444         src  = registerName register tmp
4445
4446         code__2 dst = code . mkSeqInstrs [
4447             CVTxy TF Q src tmp,
4448             ST TF tmp (spRel 0),
4449             LD Q dst (spRel 0)]
4450     in
4451     return (Any IntRep code__2)
4452
4453 #endif /* alpha_TARGET_ARCH */
4454
4455 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4456
4457 #if i386_TARGET_ARCH
4458
4459 coerceInt2FP from to x = do
4460   (x_reg, x_code) <- getSomeReg x
4461   let
4462         opc  = case to of F32 -> GITOF; F64 -> GITOD
4463         code dst = x_code `snocOL` opc x_reg dst
4464         -- ToDo: works for non-I32 reps?
4465   -- in
4466   return (Any to code)
4467
4468 ------------
4469
4470 coerceFP2Int from to x = do
4471   (x_reg, x_code) <- getSomeReg x
4472   let
4473         opc  = case from of F32 -> GFTOI; F64 -> GDTOI
4474         code dst = x_code `snocOL` opc x_reg dst
4475         -- ToDo: works for non-I32 reps?
4476   -- in
4477   return (Any to code)
4478
4479 #endif /* i386_TARGET_ARCH */
4480
4481 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4482
4483 #if x86_64_TARGET_ARCH
4484
4485 coerceFP2Int from to x = do
4486   (x_op, x_code) <- getOperand x  -- ToDo: could be a safe operand
4487   let
4488         opc  = case from of F32 -> CVTSS2SI; F64 -> CVTSD2SI
4489         code dst = x_code `snocOL` opc x_op dst
4490   -- in
4491   return (Any to code) -- works even if the destination rep is <I32
4492
4493 coerceInt2FP from to x = do
4494   (x_op, x_code) <- getOperand x  -- ToDo: could be a safe operand
4495   let
4496         opc  = case to of F32 -> CVTSI2SS; F64 -> CVTSI2SD
4497         code dst = x_code `snocOL` opc x_op dst
4498   -- in
4499   return (Any to code) -- works even if the destination rep is <I32
4500
4501 coerceFP2FP :: MachRep -> CmmExpr -> NatM Register
4502 coerceFP2FP to x = do
4503   (x_reg, x_code) <- getSomeReg x
4504   let
4505         opc  = case to of F32 -> CVTSD2SS; F64 -> CVTSS2SD
4506         code dst = x_code `snocOL` opc x_reg dst
4507   -- in
4508   return (Any to code)
4509
4510 #endif
4511
4512 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4513
4514 #if sparc_TARGET_ARCH
4515
4516 coerceInt2FP pk1 pk2 x = do
4517     (src, code) <- getSomeReg x
4518     let
4519         code__2 dst = code `appOL` toOL [
4520             ST pk1 src (spRel (-2)),
4521             LD pk1 (spRel (-2)) dst,
4522             FxTOy pk1 pk2 dst dst]
4523     return (Any pk2 code__2)
4524
4525 ------------
4526 coerceFP2Int pk fprep x = do
4527     (src, code) <- getSomeReg x
4528     reg <- getNewRegNat fprep
4529     tmp <- getNewRegNat pk
4530     let
4531         code__2 dst = ASSERT(fprep == F64 || fprep == F32)
4532             code `appOL` toOL [
4533             FxTOy fprep pk src tmp,
4534             ST pk tmp (spRel (-2)),
4535             LD pk (spRel (-2)) dst]
4536     return (Any pk code__2)
4537
4538 ------------
4539 coerceDbl2Flt x = do
4540     (src, code) <- getSomeReg x
4541     return (Any F32 (\dst -> code `snocOL` FxTOy F64 F32 src dst)) 
4542
4543 ------------
4544 coerceFlt2Dbl x = do
4545     (src, code) <- getSomeReg x
4546     return (Any F64 (\dst -> code `snocOL` FxTOy F32 F64 src dst))
4547
4548 #endif /* sparc_TARGET_ARCH */
4549
4550 #if powerpc_TARGET_ARCH
4551 coerceInt2FP fromRep toRep x = do
4552     (src, code) <- getSomeReg x
4553     lbl <- getNewLabelNat
4554     itmp <- getNewRegNat I32
4555     ftmp <- getNewRegNat F64
4556     dynRef <- cmmMakeDynamicReference addImportNat False lbl
4557     Amode addr addr_code <- getAmode dynRef
4558     let
4559         code' dst = code `appOL` maybe_exts `appOL` toOL [
4560                 LDATA ReadOnlyData
4561                                 [CmmDataLabel lbl,
4562                                  CmmStaticLit (CmmInt 0x43300000 I32),
4563                                  CmmStaticLit (CmmInt 0x80000000 I32)],
4564                 XORIS itmp src (ImmInt 0x8000),
4565                 ST I32 itmp (spRel 3),
4566                 LIS itmp (ImmInt 0x4330),
4567                 ST I32 itmp (spRel 2),
4568                 LD F64 ftmp (spRel 2)
4569             ] `appOL` addr_code `appOL` toOL [
4570                 LD F64 dst addr,
4571                 FSUB F64 dst ftmp dst
4572             ] `appOL` maybe_frsp dst
4573             
4574         maybe_exts = case fromRep of
4575                         I8 ->  unitOL $ EXTS I8 src src
4576                         I16 -> unitOL $ EXTS I16 src src
4577                         I32 -> nilOL
4578         maybe_frsp dst = case toRep of
4579                         F32 -> unitOL $ FRSP dst dst
4580                         F64 -> nilOL
4581     return (Any toRep code')
4582
4583 coerceFP2Int fromRep toRep x = do
4584     -- the reps don't really matter: F*->F64 and I32->I* are no-ops
4585     (src, code) <- getSomeReg x
4586     tmp <- getNewRegNat F64
4587     let
4588         code' dst = code `appOL` toOL [
4589                 -- convert to int in FP reg
4590             FCTIWZ tmp src,
4591                 -- store value (64bit) from FP to stack
4592             ST F64 tmp (spRel 2),
4593                 -- read low word of value (high word is undefined)
4594             LD I32 dst (spRel 3)]       
4595     return (Any toRep code')
4596 #endif /* powerpc_TARGET_ARCH */
4597
4598
4599 -- -----------------------------------------------------------------------------
4600 -- eXTRA_STK_ARGS_HERE
4601
4602 -- We (allegedly) put the first six C-call arguments in registers;
4603 -- where do we start putting the rest of them?
4604
4605 -- Moved from MachInstrs (SDM):
4606
4607 #if alpha_TARGET_ARCH || sparc_TARGET_ARCH
4608 eXTRA_STK_ARGS_HERE :: Int
4609 eXTRA_STK_ARGS_HERE
4610   = IF_ARCH_alpha(0, IF_ARCH_sparc(23, ???))
4611 #endif
4612