NCG: Split out joinToTargets from linear alloctor into its own module.
[ghc-hetmet.git] / compiler / nativeGen / RegAllocInfo.hs
index 4cb688a..57c9ce6 100644 (file)
@@ -1,3 +1,10 @@
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 -----------------------------------------------------------------------------
 --
 -- Machine-specific parts of the register allocator
@@ -14,6 +21,7 @@ module RegAllocInfo (
        regUsage,
        patchRegs,
        jumpDests,
+       isJumpish,
        patchJump,
        isRegRegMove,
 
@@ -28,14 +36,14 @@ module RegAllocInfo (
 
 #include "HsVersions.h"
 
+import BlockId
 import Cmm
 import CLabel
-import MachOp           ( MachRep(..), wordRep )
 import MachInstrs
 import MachRegs
 import Outputable
 import Constants       ( rESERVED_C_STACK_BYTES )
-import FastTypes
+import FastBool
 
 -- -----------------------------------------------------------------------------
 -- RegUsage type
@@ -69,6 +77,8 @@ interesting (RealReg i)       = isFastTrue (freeReg i)
 
 #if alpha_TARGET_ARCH
 regUsage instr = case instr of
+    SPILL  reg slot    -> usage ([reg], [])
+    RELOAD slot reg    -> usage ([], [reg])
     LD B reg addr      -> usage (regAddr addr, [reg, t9])
     LD Bu reg addr     -> usage (regAddr addr, [reg, t9])
 --  LD W reg addr      -> usage (regAddr addr, [reg, t9]) : UNUSED
@@ -202,13 +212,13 @@ regUsage instr = case instr of
     GMUL   sz s1 s2 dst        -> mkRU [s1,s2] [dst]
     GDIV   sz s1 s2 dst        -> mkRU [s1,s2] [dst]
 
-    GCMP   sz src1 src2        -> mkRUR [src1,src2]
-    GABS   sz src dst  -> mkRU [src] [dst]
-    GNEG   sz src dst  -> mkRU [src] [dst]
-    GSQRT  sz src dst  -> mkRU [src] [dst]
-    GSIN   sz src dst  -> mkRU [src] [dst]
-    GCOS   sz src dst  -> mkRU [src] [dst]
-    GTAN   sz src dst  -> mkRU [src] [dst]
+    GCMP   sz src1 src2   -> mkRUR [src1,src2]
+    GABS   sz src dst     -> mkRU [src] [dst]
+    GNEG   sz src dst     -> mkRU [src] [dst]
+    GSQRT  sz src dst     -> mkRU [src] [dst]
+    GSIN   sz _ _ src dst -> mkRU [src] [dst]
+    GCOS   sz _ _ src dst -> mkRU [src] [dst]
+    GTAN   sz _ _ src dst -> mkRU [src] [dst]
 #endif
 
 #if x86_64_TARGET_ARCH
@@ -226,6 +236,8 @@ regUsage instr = case instr of
 
     COMMENT _          -> noUsage
     DELTA   _           -> noUsage
+    SPILL   reg slot   -> mkRU [reg] []
+    RELOAD  slot reg   -> mkRU []    [reg]
 
     _other             -> panic "regUsage: unrecognised instr"
 
@@ -275,13 +287,19 @@ regUsage instr = case instr of
 #if sparc_TARGET_ARCH
 
 regUsage instr = case instr of
+    SPILL reg slot     -> usage ([reg], [])
+    RELOAD slot reg    -> usage ([], [reg])
+
     LD    sz addr reg          -> usage (regAddr addr, [reg])
     ST    sz reg addr          -> usage (reg : regAddr addr, [])
     ADD   x cc r1 ar r2        -> usage (r1 : regRI ar, [r2])
     SUB   x cc r1 ar r2        -> usage (r1 : regRI ar, [r2])
     UMUL    cc r1 ar r2        -> usage (r1 : regRI ar, [r2])
     SMUL    cc r1 ar r2        -> usage (r1 : regRI ar, [r2])
+    UDIV    cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
+    SDIV    cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
     RDY   rd            -> usage ([], [rd])
+    WRY   r1 r2         -> usage ([r1, r2], [])
     AND   b r1 ar r2   -> usage (r1 : regRI ar, [r2])
     ANDN  b r1 ar r2   -> usage (r1 : regRI ar, [r2])
     OR    b r1 ar r2           -> usage (r1 : regRI ar, [r2])
@@ -303,8 +321,8 @@ regUsage instr = case instr of
     FSUB  s r1 r2 r3   -> usage ([r1, r2], [r3])
     FxTOy s1 s2 r1 r2  -> usage ([r1], [r2])
 
-    -- We assume that all local jumps will be BI/BF.  JMP must be out-of-line.
-    JMP   addr                 -> usage (regAddr addr, [])
+    JMP     addr       -> usage (regAddr addr, [])
+    JMP_TBL addr ids    -> usage (regAddr addr, [])
 
     CALL  (Left imm)  n True  -> noUsage
     CALL  (Left imm)  n False -> usage (argRegs n, callClobberedRegs)
@@ -327,6 +345,9 @@ regUsage instr = case instr of
 #if powerpc_TARGET_ARCH
 
 regUsage instr = case instr of
+    SPILL  reg slot    -> usage ([reg], [])
+    RELOAD slot reg    -> usage ([], [reg])
+
     LD    sz reg addr          -> usage (regAddr addr, [reg])
     LA    sz reg addr          -> usage (regAddr addr, [reg])
     ST    sz reg addr          -> usage (reg : regAddr addr, [])
@@ -404,11 +425,51 @@ jumpDests insn acc
         BCC _ id        -> id : acc
         BCCFAR _ id     -> id : acc
         BCTR targets    -> targets ++ acc
+#elif sparc_TARGET_ARCH
+       BI   _ _ id     -> id : acc
+       BF   _ _ id     -> id : acc
+       JMP_TBL _ ids   -> ids ++ acc
+#else
+#error "RegAllocInfo.jumpDests not finished"
 #endif
        _other          -> acc
 
-patchJump :: Instr -> BlockId -> BlockId -> Instr
 
+-- | 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.
+--
+isJumpish :: Instr -> Bool
+isJumpish instr
+ = case instr of
+#if i386_TARGET_ARCH || x86_64_TARGET_ARCH
+       JMP{}           -> True
+       JXX{}           -> True
+       JXX_GBL{}       -> True
+       JMP_TBL{}       -> True
+       CALL{}          -> True
+
+#elif powerpc_TARGET_ARCH
+       BCC{}           -> True
+       BCCFAR{}        -> True
+       JMP{}           -> True
+       
+#elif sparc_TARGET_ARCH
+       BI{}            -> True
+       BF{}            -> True
+       JMP{}           -> True
+       JMP_TBL{}       -> True
+       CALL{}          -> True
+#else
+#error "RegAllocInfo.isJumpish: not implemented for this architecture"
+#endif
+       _               -> False
+       
+
+-- | 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
 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
@@ -418,6 +479,14 @@ patchJump insn old new
         BCC cc id | id == old -> BCC cc new
         BCCFAR cc id | id == old -> BCCFAR cc new
         BCTR targets -> error "Cannot patch BCTR"
+#elif sparc_TARGET_ARCH
+       BI cc annul id
+        | id == old    -> BI cc annul new
+        
+       BF cc annul id
+        | id == old    -> BF cc annul new
+#else
+#error "RegAllocInfo.patchJump not finished"
 #endif
        _other          -> insn
 
@@ -471,6 +540,8 @@ patchRegs :: Instr -> (Reg -> Reg) -> Instr
 #if alpha_TARGET_ARCH
 
 patchRegs instr env = case instr of
+    SPILL  reg slot    -> SPILL (env reg) slot
+    RELOAD slot reg    -> RELOAD slot (env reg)
     LD sz reg addr -> LD sz (env reg) (fixAddr addr)
     LDA reg addr -> LDA (env reg) (fixAddr addr)
     LDAH reg addr -> LDAH (env reg) (fixAddr addr)
@@ -580,9 +651,9 @@ patchRegs instr env = case instr of
     GABS sz src dst    -> GABS sz (env src) (env dst)
     GNEG sz src dst    -> GNEG sz (env src) (env dst)
     GSQRT sz src dst   -> GSQRT sz (env src) (env dst)
-    GSIN sz src dst    -> GSIN sz (env src) (env dst)
-    GCOS sz src dst    -> GCOS sz (env src) (env dst)
-    GTAN sz src dst    -> GTAN sz (env src) (env dst)
+    GSIN sz l1 l2 src dst      -> GSIN sz l1 l2 (env src) (env dst)
+    GCOS sz l1 l2 src dst      -> GCOS sz l1 l2 (env src) (env dst)
+    GTAN sz l1 l2 src dst      -> GTAN sz l1 l2 (env src) (env dst)
 #endif
 
 #if x86_64_TARGET_ARCH
@@ -604,6 +675,9 @@ patchRegs instr env = case instr of
     NOP                        -> instr
     COMMENT _          -> instr
     DELTA _            -> instr
+    SPILL  reg slot    -> SPILL (env reg) slot
+    RELOAD slot reg    -> RELOAD slot (env reg)
+
     JXX _ _            -> instr
     JXX_GBL _ _                -> instr
     CLTD _             -> instr
@@ -634,13 +708,18 @@ patchRegs instr env = case instr of
 #if sparc_TARGET_ARCH
 
 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)
@@ -661,7 +740,10 @@ patchRegs instr env = case instr of
     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     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
@@ -677,6 +759,9 @@ patchRegs instr env = case instr of
 #if powerpc_TARGET_ARCH
 
 patchRegs instr env = case instr of
+    SPILL reg slot     -> SPILL (env reg) slot
+    RELOAD slot reg    -> RELOAD slot (env reg)
+
     LD    sz reg addr   -> LD sz (env reg) (fixAddr addr)
     LA    sz reg addr   -> LA sz (env reg) (fixAddr addr)
     ST    sz reg addr   -> ST sz (env reg) (fixAddr addr)
@@ -741,28 +826,36 @@ patchRegs instr env = case instr of
 -- by assigning the src and dest temporaries to the same real register.
 
 isRegRegMove :: Instr -> Maybe (Reg,Reg)
+
 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
 -- TMP:
 isRegRegMove (MOV _ (OpReg r1) (OpReg r2)) = Just (r1,r2)
+
 #elif powerpc_TARGET_ARCH
 isRegRegMove (MR dst src) = Just (src,dst)
-#else
-#warning ToDo: isRegRegMove
+
+#elif sparc_TARGET_ARCH
+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
 #endif
-isRegRegMove _ = Nothing
+isRegRegMove _  = Nothing
 
 -- -----------------------------------------------------------------------------
 -- Generating spill instructions
 
 mkSpillInstr
-   :: Reg              -- register to spill (should be a real)
+   :: Reg              -- register to spill
    -> Int              -- current stack delta
    -> Int              -- spill slot to use
    -> Instr
 mkSpillInstr reg delta slot
- -- = ASSERT(isRealReg reg)                    -- BUGS: used for graph coloring: is this ok?
-  = let        
-        off     = spillSlotToOffset slot
+  = let        off     = spillSlotToOffset slot
     in
 #ifdef alpha_TARGET_ARCH
     {-Alpha: spill below the stack pointer (?)-}
@@ -771,14 +864,14 @@ mkSpillInstr reg delta slot
 #ifdef i386_TARGET_ARCH
     let off_w = (off-delta) `div` 4
     in case regClass reg of
-          RcInteger -> MOV I32 (OpReg reg) (OpAddr (spRel off_w))
-          _         -> GST F80 reg (spRel off_w) {- RcFloat/RcDouble -}
+          RcInteger -> MOV II32 (OpReg reg) (OpAddr (spRel off_w))
+          _         -> GST FF80 reg (spRel off_w) {- RcFloat/RcDouble -}
 #endif
 #ifdef x86_64_TARGET_ARCH
     let off_w = (off-delta) `div` 8
     in case regClass reg of
-          RcInteger -> MOV I64 (OpReg reg) (OpAddr (spRel off_w))
-          RcDouble  -> MOV F64 (OpReg reg) (OpAddr (spRel off_w))
+          RcInteger -> MOV II64 (OpReg reg) (OpAddr (spRel off_w))
+          RcDouble  -> MOV FF64 (OpReg reg) (OpAddr (spRel off_w))
                -- ToDo: will it work to always spill as a double?
                -- does that cause a stall if the data was a float?
 #endif
@@ -786,28 +879,26 @@ mkSpillInstr reg delta slot
        {-SPARC: spill below frame pointer leaving 2 words/spill-}
                         let{off_w = 1 + (off `div` 4);
                             sz = case regClass reg of {
-                                    RcInteger -> I32;
-                                   RcFloat   -> F32;
-                                    RcDouble  -> F64}}
-                        in ST sz reg (fpRel (- off_w))
+                                    RcInteger -> II32;
+                                   RcFloat   -> FF32;
+                                    RcDouble  -> FF64;}}
+                        in ST sz reg (fpRel (negate off_w))
 #endif
 #ifdef powerpc_TARGET_ARCH
     let sz = case regClass reg of
-                RcInteger -> I32
-                RcDouble -> F64
+                RcInteger -> II32
+                RcDouble  -> FF64
     in ST sz reg (AddrRegImm sp (ImmInt (off-delta)))
 #endif
 
 
 mkLoadInstr
-   :: Reg              -- register to load (should be a real)
+   :: Reg              -- register to load
    -> Int              -- current stack delta
    -> Int              -- spill slot to use
    -> Instr
 mkLoadInstr reg delta slot
- -- = ASSERT(isRealReg reg)                    -- BUGS: used for graph coloring: is this ok?
-  = let
-        off     = spillSlotToOffset slot
+  = let off     = spillSlotToOffset slot
     in
 #if alpha_TARGET_ARCH
         LD  sz dyn (spRel (- (off `div` 8)))
@@ -815,27 +906,27 @@ mkLoadInstr reg delta slot
 #if i386_TARGET_ARCH
        let off_w = (off-delta) `div` 4
         in case regClass reg of {
-              RcInteger -> MOV I32 (OpAddr (spRel off_w)) (OpReg reg);
-              _         -> GLD F80 (spRel off_w) reg} {- RcFloat/RcDouble -}
+              RcInteger -> MOV II32 (OpAddr (spRel off_w)) (OpReg reg);
+              _         -> GLD FF80 (spRel off_w) reg} {- RcFloat/RcDouble -}
 #endif
 #if x86_64_TARGET_ARCH
        let off_w = (off-delta) `div` 8
         in case regClass reg of
-              RcInteger -> MOV I64 (OpAddr (spRel off_w)) (OpReg reg)
-              _         -> MOV F64 (OpAddr (spRel off_w)) (OpReg reg)
+              RcInteger -> MOV II64 (OpAddr (spRel off_w)) (OpReg reg)
+              _         -> MOV FF64 (OpAddr (spRel off_w)) (OpReg reg)
 #endif
 #if sparc_TARGET_ARCH
         let{off_w = 1 + (off `div` 4);
             sz = case regClass reg of {
-                   RcInteger -> I32;
-                  RcFloat   -> F32;
-                   RcDouble  -> F64}}
+                   RcInteger -> II32;
+                  RcFloat   -> FF32;
+                   RcDouble  -> FF64}}
         in LD sz (fpRel (- off_w)) reg
 #endif
 #if powerpc_TARGET_ARCH
     let sz = case regClass reg of
-                RcInteger -> I32
-                RcDouble -> F64
+                RcInteger -> II32
+                RcDouble  -> FF64
     in LD sz reg (AddrRegImm sp (ImmInt (off-delta)))
 #endif
 
@@ -846,14 +937,21 @@ mkRegRegMoveInstr
 mkRegRegMoveInstr src dst
 #if i386_TARGET_ARCH || x86_64_TARGET_ARCH
     = case regClass src of
-        RcInteger -> MOV wordRep (OpReg src) (OpReg dst)
+        RcInteger -> MOV wordSize (OpReg src) (OpReg dst)
 #if i386_TARGET_ARCH
         RcDouble  -> GMOV src dst
 #else
-        RcDouble  -> MOV F64 (OpReg src) (OpReg dst)
+        RcDouble  -> MOV FF64 (OpReg src) (OpReg dst)
 #endif
 #elif powerpc_TARGET_ARCH
     = MR dst src
+#elif sparc_TARGET_ARCH
+    = case regClass src of
+       RcInteger -> ADD  False False src (RIReg g0) dst
+       RcDouble  -> FMOV FF64 src dst
+       RcFloat   -> FMOV FF32  src dst
+#else
+#error ToDo: mkRegRegMoveInstr
 #endif
 
 mkBranchInstr
@@ -868,7 +966,7 @@ mkBranchInstr id = [JXX ALWAYS id]
 #endif
 
 #if sparc_TARGET_ARCH
-mkBranchInstr (BlockId id) = [BI ALWAYS False (ImmCLbl (mkAsmTempLabel id)), NOP]
+mkBranchInstr id = [BI ALWAYS False id, NOP]
 #endif
 
 #if powerpc_TARGET_ARCH