NCG: validate fixes for i386-darwin
[ghc-hetmet.git] / compiler / nativeGen / SPARC / RegInfo.hs
index 3d9614d..025e302 100644 (file)
 -----------------------------------------------------------------------------
 
 module SPARC.RegInfo (
-       -- machine specific 
-       RegUsage(..),
-       noUsage,
-       regUsage,
-       patchRegs,
-       jumpDests,
-       isJumpish,
-       patchJump,
-       isRegRegMove,
+       mkVReg,
+
+       riZero,
+       fpRelEA,
+       moveSp,
+       fPair,
+
+       shortcutStatic,
+       regDotColor,
 
         JumpDest(..), 
        canShortcut, 
-       shortcutJump, 
-
-       mkSpillInstr,
-       mkLoadInstr,
-       mkRegRegMoveInstr,
-       mkBranchInstr,
-       
-       spillSlotSize,
-       maxSpillSlots,
-       spillSlotToOffset               
+       shortcutJump,
 )
 
 where
 
+import SPARC.Instr
+import SPARC.Regs
+import RegClass
+import Reg
+import Size
 
-#include "nativeGen/NCG.h"
-#include "HsVersions.h"
-
+import Constants       (wORD_SIZE)
+import Cmm
+import CLabel
 import BlockId
-import Instrs
-import Regs
 import Outputable
-import Constants       ( rESERVED_C_STACK_BYTES )
-import FastBool
-
-
--- -----------------------------------------------------------------------------
--- RegUsage type
-
--- @regUsage@ returns the sets of src and destination registers used
--- by a particular instruction.  Machine registers that are
--- pre-allocated to stgRegs are filtered out, because they are
--- uninteresting from a register allocation standpoint.  (We wouldn't
--- want them to end up on the free list!)  As far as we are concerned,
--- the fixed registers simply don't exist (for allocation purposes,
--- anyway).
-
--- regUsage doesn't need to do any trickery for jumps and such.  Just
--- state precisely the regs read and written by that insn.  The
--- consequences of control flow transfers, as far as register
--- allocation goes, are taken care of by the register allocator.
-
-data RegUsage = RU [Reg] [Reg]
-
-noUsage :: RegUsage
-noUsage  = RU [] []
-
-regUsage :: Instr -> RegUsage
-
-regUsage instr = case instr of
-    SPILL  reg _       -> usage ([reg], [])
-    RELOAD _   reg     -> usage ([], [reg])
-
-    LD    _ addr reg   -> usage (regAddr addr, [reg])
-    ST    _ reg addr   -> usage (reg : regAddr addr, [])
-    ADD   _ _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    SUB   _ _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    UMUL    _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    SMUL    _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    UDIV    _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    SDIV    _ r1 ar r2 -> usage (r1 : regRI ar, [r2])
-    RDY   rd            -> usage ([], [rd])
-    WRY   r1 r2         -> usage ([r1, r2], [])
-    AND   _ r1 ar r2   -> usage (r1 : regRI ar, [r2])
-    ANDN  _ r1 ar r2   -> usage (r1 : regRI ar, [r2])
-    OR    _ r1 ar r2           -> usage (r1 : regRI ar, [r2])
-    ORN   _ r1 ar r2   -> usage (r1 : regRI ar, [r2])
-    XOR   _ r1 ar r2   -> usage (r1 : regRI ar, [r2])
-    XNOR  _ r1 ar r2   -> usage (r1 : regRI ar, [r2])
-    SLL   r1 ar r2     -> usage (r1 : regRI ar, [r2])
-    SRL   r1 ar r2     -> usage (r1 : regRI ar, [r2])
-    SRA   r1 ar r2     -> usage (r1 : regRI ar, [r2])
-    SETHI _ reg        -> usage ([], [reg])
-    FABS  _ r1 r2      -> usage ([r1], [r2])
-    FADD  _ r1 r2 r3   -> usage ([r1, r2], [r3])
-    FCMP  _ _  r1 r2   -> usage ([r1, r2], [])
-    FDIV  _ r1 r2 r3   -> usage ([r1, r2], [r3])
-    FMOV  _ r1 r2      -> usage ([r1], [r2])
-    FMUL  _ r1 r2 r3   -> usage ([r1, r2], [r3])
-    FNEG  _ r1 r2      -> usage ([r1], [r2])
-    FSQRT _ r1 r2      -> usage ([r1], [r2])
-    FSUB  _ r1 r2 r3   -> usage ([r1, r2], [r3])
-    FxTOy _ _  r1 r2   -> usage ([r1], [r2])
-
-    JMP     addr       -> usage (regAddr addr, [])
-    JMP_TBL addr _      -> usage (regAddr addr, [])
-
-    CALL  (Left _  )  _ True  -> noUsage
-    CALL  (Left _  )  n False -> usage (argRegs n, callClobberedRegs)
-    CALL  (Right reg) _ True  -> usage ([reg], [])
-    CALL  (Right reg) n False -> usage (reg : (argRegs n), callClobberedRegs)
-
-    _                  -> noUsage
-  where
-    usage (src, dst) = RU (filter interesting src)
-                        (filter interesting dst)
-
-    regAddr (AddrRegReg r1 r2) = [r1, r2]
-    regAddr (AddrRegImm r1 _)  = [r1]
-
-    regRI (RIReg r) = [r]
-    regRI  _   = []
-
-
-interesting :: Reg -> Bool
-interesting (VirtualRegI  _)  = True
-interesting (VirtualRegHi _)  = True
-interesting (VirtualRegF  _)  = True
-interesting (VirtualRegD  _)  = True
-interesting (RealReg i)       = isFastTrue (freeReg i)
-
-
--- -----------------------------------------------------------------------------
--- 'patchRegs' function
-
--- 'patchRegs' takes an instruction and applies the given mapping to
--- all the register references.
-
-patchRegs :: Instr -> (Reg -> Reg) -> Instr
-
-patchRegs instr env = case instr of
-    SPILL reg slot     -> SPILL (env reg) slot
-    RELOAD slot reg    -> RELOAD slot (env reg)
-    LD    sz addr reg   -> LD sz (fixAddr addr) (env reg)
-    ST    sz reg addr   -> ST sz (env reg) (fixAddr addr)
-    ADD   x cc r1 ar r2 -> ADD x cc (env r1) (fixRI ar) (env r2)
-    SUB   x cc r1 ar r2 -> SUB x cc (env r1) (fixRI ar) (env r2)
-    UMUL    cc r1 ar r2        -> UMUL cc (env r1) (fixRI ar) (env r2)
-    SMUL    cc r1 ar r2        -> SMUL cc (env r1) (fixRI ar) (env r2)
-    UDIV    cc r1 ar r2        -> UDIV cc (env r1) (fixRI ar) (env r2)
-    SDIV    cc r1 ar r2        -> SDIV cc (env r1) (fixRI ar) (env r2)
-    RDY   rd            -> RDY (env rd)
-    WRY   r1 r2                -> WRY (env r1) (env r2)
-    AND   b r1 ar r2    -> AND b (env r1) (fixRI ar) (env r2)
-    ANDN  b r1 ar r2    -> ANDN b (env r1) (fixRI ar) (env r2)
-    OR    b r1 ar r2    -> OR b (env r1) (fixRI ar) (env r2)
-    ORN   b r1 ar r2    -> ORN b (env r1) (fixRI ar) (env r2)
-    XOR   b r1 ar r2    -> XOR b (env r1) (fixRI ar) (env r2)
-    XNOR  b r1 ar r2    -> XNOR b (env r1) (fixRI ar) (env r2)
-    SLL   r1 ar r2      -> SLL (env r1) (fixRI ar) (env r2)
-    SRL   r1 ar r2      -> SRL (env r1) (fixRI ar) (env r2)
-    SRA   r1 ar r2      -> SRA (env r1) (fixRI ar) (env r2)
-    SETHI imm reg       -> SETHI imm (env reg)
-    FABS  s r1 r2       -> FABS s (env r1) (env r2)
-    FADD  s r1 r2 r3    -> FADD s (env r1) (env r2) (env r3)
-    FCMP  e s r1 r2     -> FCMP e s (env r1) (env r2)
-    FDIV  s r1 r2 r3    -> FDIV s (env r1) (env r2) (env r3)
-    FMOV  s r1 r2       -> FMOV s (env r1) (env r2)
-    FMUL  s r1 r2 r3    -> FMUL s (env r1) (env r2) (env r3)
-    FNEG  s r1 r2       -> FNEG s (env r1) (env r2)
-    FSQRT s r1 r2       -> FSQRT s (env r1) (env r2)
-    FSUB  s r1 r2 r3    -> FSUB s (env r1) (env r2) (env r3)
-    FxTOy s1 s2 r1 r2   -> FxTOy s1 s2 (env r1) (env r2)
-
-    JMP     addr        -> JMP     (fixAddr addr)
-    JMP_TBL addr ids    -> JMP_TBL (fixAddr addr) ids
-
-    CALL  (Left i) n t  -> CALL (Left i) n t
-    CALL  (Right r) n t -> CALL (Right (env r)) n t
-    _ -> instr
-  where
-    fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)
-    fixAddr (AddrRegImm r1 i)  = AddrRegImm (env r1) i
-
-    fixRI (RIReg r) = RIReg (env r)
-    fixRI other        = other
-
+import Unique
 
--- -----------------------------------------------------------------------------
--- Determine the possible destinations from the current instruction.
 
--- (we always assume that the next instruction is also a valid destination;
--- if this isn't the case then the jump should be at the end of the basic
--- block).
+-- | Make a virtual reg with this size.
+mkVReg :: Unique -> Size -> Reg
+mkVReg u size
+       | not (isFloatSize size) 
+       = VirtualRegI u
 
-jumpDests :: Instr -> [BlockId] -> [BlockId]
-jumpDests insn acc
-  = case insn of
-       BI   _ _ id     -> id : acc
-       BF   _ _ id     -> id : acc
-       JMP_TBL _ ids   -> ids ++ acc
-       _other          -> acc
+       | otherwise
+       = case size of
+               FF32    -> VirtualRegF u
+               FF64    -> VirtualRegD u
+               _       -> panic "mkVReg"
 
 
--- | Check whether a particular instruction is a jump, branch or call instruction (jumpish)
---     We can't just use jumpDests above because the jump might take its arg,
---     so the instr won't contain a blockid.
+-- | Check if a RI represents a zero value.
+--     - a literal zero
+--     - register %g0, which is always zero.
 --
-isJumpish :: Instr -> Bool
-isJumpish instr
- = case instr of
-       BI{}            -> True
-       BF{}            -> True
-       JMP{}           -> True
-       JMP_TBL{}       -> True
-       CALL{}          -> True
-       _               -> False
+riZero :: RI -> Bool
+riZero (RIImm (ImmInt 0))          = True
+riZero (RIImm (ImmInteger 0))      = True
+riZero (RIReg (RealReg 0))          = True
+riZero _                           = False
+
+
+-- | Calculate the effective address which would be used by the
+--     corresponding fpRel sequence.  fpRel is in MachRegs.lhs,
+--     alas -- can't have fpRelEA here because of module dependencies.
+fpRelEA :: Int -> Reg -> Instr
+fpRelEA n dst
+   = ADD False False fp (RIImm (ImmInt (n * wORD_SIZE))) dst
+
+
+-- | Code to shift the stack pointer by n words.
+moveSp :: Int -> Instr
+moveSp n
+   = ADD False False sp (RIImm (ImmInt (n * wORD_SIZE))) sp
+
+
+-- | Produce the second-half-of-a-double register given the first half.
+fPair :: Reg -> Maybe Reg
+fPair (RealReg n) 
+       | n >= 32 && n `mod` 2 == 0  = Just (RealReg (n+1))
+
+fPair (VirtualRegD u)
+       = Just (VirtualRegHi u)
+
+fPair _
+       = trace ("MachInstrs.fPair: can't get high half of supposed double reg ") 
+               Nothing
+
+-- Here because it knows about JumpDest
+shortcutStatic :: (BlockId -> Maybe JumpDest) -> CmmStatic -> CmmStatic
+shortcutStatic fn (CmmStaticLit (CmmLabel lab))
+  | Just uq <- maybeAsmTemp lab 
+  = CmmStaticLit (CmmLabel (shortBlockId fn (BlockId uq)))
+shortcutStatic fn (CmmStaticLit (CmmLabelDiffOff lbl1 lbl2 off))
+  | Just uq <- maybeAsmTemp lbl1
+  = CmmStaticLit (CmmLabelDiffOff (shortBlockId fn (BlockId uq)) lbl2 off)
+        -- slightly dodgy, we're ignoring the second label, but this
+        -- works with the way we use CmmLabelDiffOff for jump tables now.
+shortcutStatic _ other_static
+        = other_static
+
+shortBlockId :: (BlockId -> Maybe JumpDest) -> BlockId -> CLabel
+shortBlockId fn blockid@(BlockId uq) =
+   case fn blockid of
+      Nothing -> mkAsmTempLabel uq
+      Just (DestBlockId blockid')  -> shortBlockId fn blockid'
+      Just (DestImm (ImmCLbl lbl)) -> lbl
+      _other -> panic "shortBlockId"
+
+
+regDotColor :: Reg -> SDoc
+regDotColor reg
+ = case regClass reg of
+       RcInteger       -> text "blue"
+       RcFloat         -> text "red"
+       RcDouble        -> text "green"
 
 
--- | Change the destination of this jump instruction
---     Used in joinToTargets in the linear allocator, when emitting fixup code
---     for join points.
-patchJump :: Instr -> BlockId -> BlockId -> Instr
-patchJump insn old new
-  = case insn of
-       BI cc annul id
-        | id == old    -> BI cc annul new
-        
-       BF cc annul id
-        | id == old    -> BF cc annul new
-
-       _other          -> insn
-
-
--- -----------------------------------------------------------------------------
--- Detecting reg->reg moves
-
--- The register allocator attempts to eliminate reg->reg moves whenever it can,
--- by assigning the src and dest temporaries to the same real register.
-
-isRegRegMove :: Instr -> Maybe (Reg,Reg)
-isRegRegMove instr
- = case instr of
-       ADD False False src (RIReg src2) dst
-        | g0 == src2           -> Just (src, dst)
-
-       FMOV FF64 src dst       -> Just (src, dst)
-       FMOV FF32  src dst      -> Just (src, dst)
-       _                       -> Nothing
-
 
 data JumpDest = DestBlockId BlockId | DestImm Imm
 
@@ -258,82 +127,3 @@ canShortcut _ = Nothing
 
 shortcutJump :: (BlockId -> Maybe JumpDest) -> Instr -> Instr
 shortcutJump _ other = other
-
-
-
-
--- -----------------------------------------------------------------------------
--- Generating spill instructions
-
--- SPARC: spill below frame pointer leaving 2 words/spill
-mkSpillInstr
-   :: Reg              -- register to spill
-   -> Int              -- current stack delta
-   -> Int              -- spill slot to use
-   -> Instr
-
-mkSpillInstr reg _ slot
-  = let        off     = spillSlotToOffset slot
-        off_w  = 1 + (off `div` 4)
-        sz     = case regClass reg of
-                       RcInteger -> II32
-                       RcFloat   -> FF32
-                       RcDouble  -> FF64
-               
-    in ST sz reg (fpRel (negate off_w))
-
-
-mkLoadInstr
-   :: Reg              -- register to load
-   -> Int              -- current stack delta
-   -> Int              -- spill slot to use
-   -> Instr
-
-mkLoadInstr reg _ slot
-  = let off     = spillSlotToOffset slot
-    in  let{off_w = 1 + (off `div` 4);
-            sz = case regClass reg of {
-                   RcInteger -> II32;
-                  RcFloat   -> FF32;
-                   RcDouble  -> FF64}}
-        in LD sz (fpRel (- off_w)) reg
-
-
-mkRegRegMoveInstr
-    :: Reg
-    -> Reg
-    -> Instr
-mkRegRegMoveInstr src dst
-    = case regClass src of
-       RcInteger -> ADD  False False src (RIReg g0) dst
-       RcDouble  -> FMOV FF64 src dst
-       RcFloat   -> FMOV FF32  src dst
-
-
-mkBranchInstr
-    :: BlockId
-    -> [Instr]
-
-mkBranchInstr id = [BI ALWAYS False id, NOP]
-
-
-spillSlotSize :: Int
-spillSlotSize = 8
-
-maxSpillSlots :: Int
-maxSpillSlots = ((rESERVED_C_STACK_BYTES - 64) `div` spillSlotSize) - 1
-
-
--- convert a spill slot number to a *byte* offset, with no sign:
--- decide on a per arch basis whether you are spilling above or below
--- the C stack pointer.
-spillSlotToOffset :: Int -> Int
-spillSlotToOffset slot
-   | slot >= 0 && slot < maxSpillSlots
-   = 64 + spillSlotSize * slot
-
-   | otherwise
-   = pprPanic "spillSlotToOffset:" 
-              (   text "invalid spill location: " <> int slot
-             $$  text "maxSpillSlots:          " <> int maxSpillSlots)
-