-- -----------------------------------------------------------------------------
module SPARC.Regs (
- -- immediate values
- Imm(..),
- strImmLit,
- litToImm,
-
- -- addressing modes
- AddrMode(..),
- addrOffset,
-
-- registers
- spRel,
- argRegs,
- allArgRegs,
- callClobberedRegs,
- allMachRegNos,
- regClass,
showReg,
+ virtualRegSqueeze,
+ realRegSqueeze,
+ classOfRealReg,
+ allRealRegs,
-- machine specific info
- fpRel,
- fits13Bits,
- largeOffsetError,
gReg, iReg, lReg, oReg, fReg,
- fp, sp, g0, g1, g2, o0, o1, f0, f6, f8, f22, f26, f27,
- nCG_FirstFloatReg,
+ fp, sp, g0, g1, g2, o0, o1, f0, f1, f6, f8, f22, f26, f27,
-- allocatable
- freeReg,
allocatableRegs,
- globalRegMaybe,
- get_GlobalReg_reg_or_addr
+ -- args
+ argRegs,
+ allArgRegs,
+ callClobberedRegs,
+
+ --
+ mkVirtualReg,
+ regDotColor
)
where
+import SPARC.RegPlate
import Reg
import RegClass
+import Size
-import CgUtils ( get_GlobalReg_addr )
-import BlockId
-import Cmm
-import CLabel ( CLabel )
-import Pretty
-import Outputable ( panic )
-import qualified Outputable
-import Constants
-import FastBool
-
-
--- immediates ------------------------------------------------------------------
+-- import PprCmm ()
--- | An immediate value.
--- Not all of these are directly representable by the machine.
--- Things like ImmLit are slurped out and put in a data segment instead.
---
-data Imm
- = ImmInt Int
-
- -- Sigh.
- | ImmInteger Integer
+import Unique
+import Outputable
+import FastTypes
+import FastBool
- -- AbstractC Label (with baggage)
- | ImmCLbl CLabel
+{-
+ The SPARC has 64 registers of interest; 32 integer registers and 32
+ floating point registers. The mapping of STG registers to SPARC
+ machine registers is defined in StgRegs.h. We are, of course,
+ prepared for any eventuality.
- -- Simple string
- | ImmLit Doc
- | ImmIndex CLabel Int
- | ImmFloat Rational
- | ImmDouble Rational
+ The whole fp-register pairing thing on sparcs is a huge nuisance. See
+ includes/stg/MachRegs.h for a description of what's going on
+ here.
+-}
- | ImmConstantSum Imm Imm
- | ImmConstantDiff Imm Imm
- | LO Imm
- | HI Imm
+-- | Get the standard name for the register with this number.
+showReg :: RegNo -> String
+showReg n
+ | n >= 0 && n < 8 = "%g" ++ show n
+ | n >= 8 && n < 16 = "%o" ++ show (n-8)
+ | n >= 16 && n < 24 = "%l" ++ show (n-16)
+ | n >= 24 && n < 32 = "%i" ++ show (n-24)
+ | n >= 32 && n < 64 = "%f" ++ show (n-32)
+ | otherwise = panic "SPARC.Regs.showReg: unknown sparc register"
--- | Create a ImmLit containing this string.
-strImmLit :: String -> Imm
-strImmLit s = ImmLit (text s)
+-- Get the register class of a certain real reg
+classOfRealReg :: RealReg -> RegClass
+classOfRealReg reg
+ = case reg of
+ RealRegSingle i
+ | i < 32 -> RcInteger
+ | otherwise -> RcFloat
+
+ RealRegPair{} -> RcDouble
--- | Convert a CmmLit to an Imm.
--- Narrow to the width: a CmmInt might be out of
--- range, but we assume that ImmInteger only contains
--- in-range values. A signed value should be fine here.
+-- | regSqueeze_class reg
+-- Calculuate the maximum number of register colors that could be
+-- denied to a node of this class due to having this reg
+-- as a neighbour.
--
-litToImm :: CmmLit -> Imm
-litToImm lit
- = case lit of
- CmmInt i w -> ImmInteger (narrowS w i)
- CmmFloat f W32 -> ImmFloat f
- CmmFloat f W64 -> ImmDouble f
- CmmLabel l -> ImmCLbl l
- CmmLabelOff l off -> ImmIndex l off
+{-# INLINE virtualRegSqueeze #-}
+virtualRegSqueeze :: RegClass -> VirtualReg -> FastInt
+
+virtualRegSqueeze cls vr
+ = case cls of
+ RcInteger
+ -> case vr of
+ VirtualRegI{} -> _ILIT(1)
+ VirtualRegHi{} -> _ILIT(1)
+ _other -> _ILIT(0)
+
+ RcFloat
+ -> case vr of
+ VirtualRegF{} -> _ILIT(1)
+ VirtualRegD{} -> _ILIT(2)
+ _other -> _ILIT(0)
+
+ RcDouble
+ -> case vr of
+ VirtualRegF{} -> _ILIT(1)
+ VirtualRegD{} -> _ILIT(1)
+ _other -> _ILIT(0)
+
+ _other -> _ILIT(0)
+
+{-# INLINE realRegSqueeze #-}
+realRegSqueeze :: RegClass -> RealReg -> FastInt
+
+realRegSqueeze cls rr
+ = case cls of
+ RcInteger
+ -> case rr of
+ RealRegSingle regNo
+ | regNo < 32 -> _ILIT(1)
+ | otherwise -> _ILIT(0)
+
+ RealRegPair{} -> _ILIT(0)
+
+ RcFloat
+ -> case rr of
+ RealRegSingle regNo
+ | regNo < 32 -> _ILIT(0)
+ | otherwise -> _ILIT(1)
+
+ RealRegPair{} -> _ILIT(2)
+
+ RcDouble
+ -> case rr of
+ RealRegSingle regNo
+ | regNo < 32 -> _ILIT(0)
+ | otherwise -> _ILIT(1)
+
+ RealRegPair{} -> _ILIT(1)
+
+ _other -> _ILIT(0)
+
+-- | All the allocatable registers in the machine,
+-- including register pairs.
+allRealRegs :: [RealReg]
+allRealRegs
+ = [ (RealRegSingle i) | i <- [0..63] ]
+ ++ [ (RealRegPair i (i+1)) | i <- [32, 34 .. 62 ] ]
- CmmLabelDiffOff l1 l2 off
- -> ImmConstantSum
- (ImmConstantDiff (ImmCLbl l1) (ImmCLbl l2))
- (ImmInt off)
- CmmBlock id -> ImmCLbl (infoTblLbl id)
- _ -> panic "SPARC.Regs.litToImm: no match"
+-- | Get the regno for this sort of reg
+gReg, lReg, iReg, oReg, fReg :: Int -> RegNo
+gReg x = x -- global regs
+oReg x = (8 + x) -- output regs
+lReg x = (16 + x) -- local regs
+iReg x = (24 + x) -- input regs
+fReg x = (32 + x) -- float regs
--- addressing modes ------------------------------------------------------------
+-- | Some specific regs used by the code generator.
+g0, g1, g2, fp, sp, o0, o1, f0, f1, f6, f8, f22, f26, f27 :: Reg
--- | Represents a memory address in an instruction.
--- Being a RISC machine, the SPARC addressing modes are very regular.
---
-data AddrMode
- = AddrRegReg Reg Reg -- addr = r1 + r2
- | AddrRegImm Reg Imm -- addr = r1 + imm
+f6 = RegReal (RealRegSingle (fReg 6))
+f8 = RegReal (RealRegSingle (fReg 8))
+f22 = RegReal (RealRegSingle (fReg 22))
+f26 = RegReal (RealRegSingle (fReg 26))
+f27 = RegReal (RealRegSingle (fReg 27))
+-- g0 is always zero, and writes to it vanish.
+g0 = RegReal (RealRegSingle (gReg 0))
+g1 = RegReal (RealRegSingle (gReg 1))
+g2 = RegReal (RealRegSingle (gReg 2))
--- | Add an integer offset to the address in an AddrMode.
---
-addrOffset :: AddrMode -> Int -> Maybe AddrMode
-addrOffset addr off
- = case addr of
- AddrRegImm r (ImmInt n)
- | fits13Bits n2 -> Just (AddrRegImm r (ImmInt n2))
- | otherwise -> Nothing
- where n2 = n + off
-
- AddrRegImm r (ImmInteger n)
- | fits13Bits n2 -> Just (AddrRegImm r (ImmInt (fromInteger n2)))
- | otherwise -> Nothing
- where n2 = n + toInteger off
+-- FP, SP, int and float return (from C) regs.
+fp = RegReal (RealRegSingle (iReg 6))
+sp = RegReal (RealRegSingle (oReg 6))
+o0 = RegReal (RealRegSingle (oReg 0))
+o1 = RegReal (RealRegSingle (oReg 1))
+f0 = RegReal (RealRegSingle (fReg 0))
+f1 = RegReal (RealRegSingle (fReg 1))
+
+-- | 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))
- AddrRegReg r (RealReg 0)
- | fits13Bits off -> Just (AddrRegImm r (ImmInt off))
- | otherwise -> Nothing
-
- _ -> Nothing
+fPair (VirtualRegD u)
+ = Just (VirtualRegHi u)
+fPair reg
+ = trace ("MachInstrs.fPair: can't get high half of supposed double reg " ++ showPpr reg)
+ Nothing
+-}
--- registers -------------------------------------------------------------------
+-- | All the regs that the register allocator can allocate to,
+-- with the the fixed use regs removed.
+--
+allocatableRegs :: [RealReg]
+allocatableRegs
+ = let isFree rr
+ = case rr of
+ RealRegSingle r
+ -> isFastTrue (freeReg r)
--- | Get an AddrMode relative to the address in sp.
--- This gives us a stack relative addressing mode for volatile
--- temporaries and for excess call arguments.
---
-spRel :: Int -- ^ stack offset in words, positive or negative
- -> AddrMode
+ RealRegPair r1 r2
+ -> isFastTrue (freeReg r1)
+ && isFastTrue (freeReg r2)
-spRel n = AddrRegImm sp (ImmInt (n * wORD_SIZE))
+ in filter isFree allRealRegs
-- | The registers to place arguments for function calls,
argRegs r
= case r of
0 -> []
- 1 -> map (RealReg . oReg) [0]
- 2 -> map (RealReg . oReg) [0,1]
- 3 -> map (RealReg . oReg) [0,1,2]
- 4 -> map (RealReg . oReg) [0,1,2,3]
- 5 -> map (RealReg . oReg) [0,1,2,3,4]
- 6 -> map (RealReg . oReg) [0,1,2,3,4,5]
+ 1 -> map (RegReal . RealRegSingle . oReg) [0]
+ 2 -> map (RegReal . RealRegSingle . oReg) [0,1]
+ 3 -> map (RegReal . RealRegSingle . oReg) [0,1,2]
+ 4 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3]
+ 5 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3,4]
+ 6 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3,4,5]
_ -> panic "MachRegs.argRegs(sparc): don't know about >6 arguments!"
--
allArgRegs :: [Reg]
allArgRegs
- = map RealReg [oReg i | i <- [0..5]]
+ = map (RegReal . RealRegSingle) [oReg i | i <- [0..5]]
-- These are the regs that we cannot assume stay alive over a C call.
--
callClobberedRegs :: [Reg]
callClobberedRegs
- = map RealReg
+ = map (RegReal . RealRegSingle)
( oReg 7 :
[oReg i | i <- [0..5]] ++
[gReg i | i <- [1..7]] ++
[fReg i | i <- [0..31]] )
--- | The RegNos corresponding to all the registers in the machine.
--- For SPARC we use f0-f22 as doubles, so pretend that the high halves
--- of these, ie f23, f25 .. don't exist.
---
-allMachRegNos :: [RegNo]
-allMachRegNos
- = ([0..31]
- ++ [32,34 .. nCG_FirstFloatReg-1]
- ++ [nCG_FirstFloatReg .. 63])
+-- | Make a virtual reg with this size.
+mkVirtualReg :: Unique -> Size -> VirtualReg
+mkVirtualReg u size
+ | not (isFloatSize size)
+ = VirtualRegI u
--- | Get the class of a register.
-{-# INLINE regClass #-}
-regClass :: Reg -> RegClass
-regClass reg
- = case reg of
- VirtualRegI _ -> RcInteger
- VirtualRegHi _ -> RcInteger
- VirtualRegF _ -> RcFloat
- VirtualRegD _ -> RcDouble
- RealReg i
- | i < 32 -> RcInteger
- | i < nCG_FirstFloatReg -> RcDouble
- | otherwise -> RcFloat
+ | otherwise
+ = case size of
+ FF32 -> VirtualRegF u
+ FF64 -> VirtualRegD u
+ _ -> panic "mkVReg"
--- | Get the standard name for the register with this number.
-showReg :: RegNo -> String
-showReg n
- | n >= 0 && n < 8 = "%g" ++ show n
- | n >= 8 && n < 16 = "%o" ++ show (n-8)
- | n >= 16 && n < 24 = "%l" ++ show (n-16)
- | n >= 24 && n < 32 = "%i" ++ show (n-24)
- | n >= 32 && n < 64 = "%f" ++ show (n-32)
- | otherwise = panic "SPARC.Regs.showReg: unknown sparc register"
-
-
--- machine specific ------------------------------------------------------------
-
--- | Get an address relative to the frame pointer.
--- This doesn't work work for offsets greater than 13 bits; we just hope for the best
---
-fpRel :: Int -> AddrMode
-fpRel n
- = AddrRegImm fp (ImmInt (n * wORD_SIZE))
+regDotColor :: RealReg -> SDoc
+regDotColor reg
+ = case classOfRealReg reg of
+ RcInteger -> text "blue"
+ RcFloat -> text "red"
+ _other -> text "green"
--- | Check whether an offset is representable with 13 bits.
-fits13Bits :: Integral a => a -> Bool
-fits13Bits x = x >= -4096 && x < 4096
-
-{-# SPECIALIZE fits13Bits :: Int -> Bool, Integer -> Bool #-}
-
-
--- | Sadness.
-largeOffsetError :: Integral a => a -> b
-largeOffsetError i
- = panic ("ERROR: SPARC native-code generator cannot handle large offset ("
- ++ show i ++ ");\nprobably because of large constant data structures;" ++
- "\nworkaround: use -fvia-C on this module.\n")
-
-
-
-{-
- The SPARC has 64 registers of interest; 32 integer registers and 32
- floating point registers. The mapping of STG registers to SPARC
- machine registers is defined in StgRegs.h. We are, of course,
- prepared for any eventuality.
-
- The whole fp-register pairing thing on sparcs is a huge nuisance. See
- fptools/ghc/includes/MachRegs.h for a description of what's going on
- here.
--}
-
-
--- | Get the regno for this sort of reg
-gReg, lReg, iReg, oReg, fReg :: Int -> RegNo
-
-gReg x = x -- global regs
-oReg x = (8 + x) -- output regs
-lReg x = (16 + x) -- local regs
-iReg x = (24 + x) -- input regs
-fReg x = (32 + x) -- float regs
-
-
--- | Some specific regs used by the code generator.
-g0, g1, g2, fp, sp, o0, o1, f0, f6, f8, f22, f26, f27 :: Reg
-
-f6 = RealReg (fReg 6)
-f8 = RealReg (fReg 8)
-f22 = RealReg (fReg 22)
-f26 = RealReg (fReg 26)
-f27 = RealReg (fReg 27)
-
-g0 = RealReg (gReg 0) -- g0 is always zero, and writes to it vanish.
-g1 = RealReg (gReg 1)
-g2 = RealReg (gReg 2)
-
--- FP, SP, int and float return (from C) regs.
-fp = RealReg (iReg 6)
-sp = RealReg (oReg 6)
-o0 = RealReg (oReg 0)
-o1 = RealReg (oReg 1)
-f0 = RealReg (fReg 0)
-
-
--- | We use he first few float regs as double precision.
--- This is the RegNo of the first float regs we use as single precision.
---
-nCG_FirstFloatReg :: RegNo
-nCG_FirstFloatReg = 54
-
+-- Hard coded freeReg / globalRegMaybe -----------------------------------------
+-- This isn't being used at the moment because we're generating
+-- these functions from the information in
+-- includes/stg/MachRegs.hs via RegPlate.hs
+
-- | Check whether a machine register is free for allocation.
--- This needs to match the info in includes/MachRegs.h otherwise modules
--- compiled with the NCG won't be compatible with via-C ones.
+-- This needs to match the info in includes/stg/MachRegs.h
+-- otherwise modules compiled with the NCG won't be compatible
+-- with via-C ones.
--
+{-
freeReg :: RegNo -> FastBool
freeReg regno
= case regno of
-- %l6(r22) - %l7(r23) are allocable --------------
-- %i0(r24) - %i5(r29)
- -- are STG regs Sp, Base, SpLim, Hp, HpLim, R6
+ -- are STG regs Sp, Base, SpLim, Hp, R6
24 -> fastBool False
25 -> fastBool False
26 -> fastBool False
27 -> fastBool False
- 28 -> fastBool False
+
+ -- %i5(r28) is allocable --------------------------
+
29 -> fastBool False
-- %i6(r30)
-- regs not matched above are allocable.
_ -> fastBool True
-
--- allocatableRegs is allMachRegNos with the fixed-use regs removed.
--- i.e., these are the regs for which we are prepared to allow the
--- register allocator to attempt to map VRegs to.
-allocatableRegs :: [RegNo]
-allocatableRegs
- = let isFree i = isFastTrue (freeReg i)
- in filter isFree allMachRegNos
-
+-}
-- | Returns Just the real register that a global register is stored in.
-- Returns Nothing if the global has no real register, and is stored
-- in the in-memory register table instead.
--
+{-
globalRegMaybe :: GlobalReg -> Maybe Reg
globalRegMaybe gg
= case gg of
Sp -> Just (RealReg 24) -- %i0
SpLim -> Just (RealReg 26) -- %i2
Hp -> Just (RealReg 27) -- %i3
- HpLim -> Just (RealReg 28) -- %i4
BaseReg -> Just (RealReg 25) -- %i1
_ -> Nothing
-
-
--- We map STG registers onto appropriate CmmExprs. Either they map
--- to real machine registers or stored as offsets from BaseReg. Given
--- a GlobalReg, get_GlobalReg_reg_or_addr produces either the real
--- register it is in, on this platform, or a CmmExpr denoting the
--- address in the register table holding it.
--- (See also get_GlobalReg_addr in CgUtils.)
-
-get_GlobalReg_reg_or_addr :: GlobalReg -> Either Reg CmmExpr
-get_GlobalReg_reg_or_addr mid
- = case globalRegMaybe mid of
- Just rr -> Left rr
- Nothing -> Right (get_GlobalReg_addr mid)
+-}